Java simpledateformat 无法解析的日期,即使格式看起来是正确的

Java simpledateformat Unparseable date, even though the format appears to be right

我遇到了一个愚蠢的问题,这是我的代码:

SimpleDateFormat dateFormat = new SimpleDateFormat("EEE MMM dd yyyy HH:mm:ss zZ",Locale.US);
System.out.println(dateFormat.format(new Date()));
try {
    wou.setDateStart(dateFormat.parse(date));
    wou.setDateEnd(dateFormat.parse(date));
} catch (ParseException e) {
    System.out.println(e.getCause() + " " + e.getMessage());
    e.printStackTrace();
}

结果如下:

2015 年 6 月 5 日,星期五 15:34:29 GMT+0000

null 无法解析的日期:"Fri Jun 05 2015 17:30:00 GMT+0000"

我的格式有什么问题?它以与我要解析的日期相同的格式输出当前日期,但一直告诉我该日期无法解析...

我为此苦苦挣扎了一个多小时,我完全迷失了...

编辑:

我无法控制我需要解析的日期(如果我这样做了,我会在源代码中将其更改为我可以使用的格式)

以下代码:

String date = request.getParameter("absencyDate");
SimpleDateFormat dateFormat = new SimpleDateFormat("EEE MMM dd yyyy HH:mm:ss z",Locale.US);
try {
    System.out.println(dateFormat.format(new Date()));
    System.out.println(date);
    System.out.println(dateFormat.parse(date));
} catch (ParseException e1) {

产生同样的错误:

2015 年 6 月 5 日星期五16:09:15格林威治标准时间

2015 年 6 月 5 日,星期五 12:30:00 GMT+0000

java.text.ParseException:无法解析的日期:"Fri Jun 05 2015 12:30:00 GMT+0000"

问题是您在日期格式中使用了 zZ。它需要一个简单的基于名称的区域 (z),然后是一个 RFC-822 区域 (Z)。

如果默认时区(或格式中设置的时区)不是 GMT,它会很好地工作,因为它只解析到那个点(匹配 z),然后解析 +0000 作为 Z.

但是当区域是 GMT 时,它实际上会尝试将它后面的部分 (+0000) 解析为 z 的一部分,因为 "GMT+hh:mm" 是一个有效区域z,但失败了。

日期格式看似正确。但是结合两种时区格式不是。它应该是一个命名时区(包括 "GMT+00:00"),或者一个 RFC 822 偏移量(不包括 "GMT" 指定)。

按照 OP 编辑​​进行编辑

所以你从某个地方得到你的 date 参数,他们用非标准的区域指定发送给你。 GMT+0000 既不匹配一般时区(应为 GMTGMT+00:00)、RFC 822 时区(应为 +0000 而没有 GMT),也不匹配 ISO 8601 时间区域(应为 +00+0000+00:00)。

如果你知道他们在约会时总是使用 GMT,我认为你能做的最好的事情是:

"EEE MMM dd yyyy HH:mm:ss 'GMT'Z"

它将 GMT 部分作为文字字符串而不是时区指示符,然后从其后的任何内容解释时区。

或者,如果生成该参数的源在您的控制之下,请修复其格式以使用与标准之一匹配的正确时区。

java.time

旧版日期时间 API(java.util 日期时间类型及其格式 API、SimpleDateFormat)已过时且容易出错。建议完全停止使用,改用java.timemodern date-time API*.

使用现代日期时间的演示 API:

import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeFormatterBuilder;
import java.util.Locale;

public class Main {
    public static void main(String args[]) {
        String dateStr = "Fri Jun 05 2015 17:30:00 GMT+0000";
        
        DateTimeFormatter dtf = new DateTimeFormatterBuilder()
                                .parseCaseInsensitive()
                                .appendPattern("EEE MMM d u H:m:s")
                                .appendLiteral(' ')
                                .appendZoneId()
                                .appendPattern("X")
                                .toFormatter(Locale.ENGLISH);
        
        ZonedDateTime zdt = ZonedDateTime.parse(dateStr, dtf);
        
        System.out.println(zdt);
    }
}

输出:

2015-06-05T17:30Z[GMT]

出于任何原因,如果您需要从 ZonedDateTime 这个对象中得到一个 java.util.Date 的对象,您可以这样做:

Date date = Date.from(zdt.toInstant());

Trail: Date Time[=46= 中了解有关 modern date-time API* 的更多信息].


* 无论出于何种原因,如果您必须坚持Java 6 或Java 7,您可以使用ThreeTen-Backport which backports most of the java.time functionality to Java 6 & 7. If you are working for an Android project and your Android API level is still not compliant with Java-8, check Java 8+ APIs available through desugaring and