解析 ISO 8601 日期格式,例如 Java 中的 2015-06-27T13:16:37.363Z

Parsing ISO 8601 date format like 2015-06-27T13:16:37.363Z in Java

我正在尝试使用 SimpleDateFormat 解析 String

这是我当前的代码:

public String getCreatedDateTime() {
    SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-ddEHH:mm:ss.zzzz");
    try {
        Date date = simpleDateFormat.parse("2015-06-27T13:16:37.363Z");
        return date.toString();
    } catch (ParseException e) {
        return "Error parsing date";
    }
}

如您所见,为了测试目的,我只是在 parse() 方法中放置了一个常量。

所以,这就是我要解析的内容:

2015-06-27T13:16:37.363Z

这是我正在使用的 SimpleDateFormat 模式:

yyyy-MM-ddEHH:mm:ss.zzzz

我不断收到 ParseException。

我知道这可能是因为末尾有 .zzzz,但我不知道 .363Z 可能代表什么,所以我只是使用了一些随机字母。坏主意。

非常感谢你的帮助。谢谢!

试试这个模式(注意末尾的 X 和中间的 'T'):

"yyyy-MM-dd'T'HH:mm:ss.SSSX"

来自 Java 的 SimpleDateFormat's documentation:

ISO 8601 Time zone:

...

For parsing, "Z" is parsed as the UTC time zone designator.

并且,从描述不同字符的部分来看:

X - Time zone - ISO 8601 time zone

编辑

如果使用 Android,则不支持“X”。

你可以使用这个模式(注意 Z 现在是一个文字):

"yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"

但随后您将获得当前时区的日期,如果需要,需要将其转换为 UTC。

tl;博士

跳过格式化模式。默认使用标准 ISO 8601 格式。

Instant.parse( "2015-06-27T13:16:37.363Z" )

ISO 8601

您的字符串格式由 ISO 8601 标准正式定义。

基本上你的问题是这个问题的重复,Converting ISO 8601-compliant String to java.util.Date

备选方案

by eugenioy 是正确的。

但是你应该知道旧的 java.util.Date/.Calendar/java.text.SimpleDateFormat classes 与 Java 捆绑在一起是出了名的麻烦,应该避免.

过时类

那些旧的 classes 现在已经过时了,首先是第三方 Joda-Time library, and now by the new java.time package (Tutorial) built into Java 8 and later (inspired by Joda-Time, defined by JSR 310, extended by the ThreeTen-Extra 项目)。

当 parsing/generating 字符串表示日期时间值时,java.time 和 Joda-Time 都使用 ISO 8601 标准作为它们的默认值。所以代码很简单,不需要自定义格式化对象。 不需要所有导致异常的格式。

时区

java.time 和 Joda-Time 都有一个分区日期时间 class,可以理解其分配的时区(与 java.util.Date 不同)。如果您不指定时区,则会指定 JVM 当前的默认时区。

请注意,JVM 当前的默认时区可以随时更改。它可以在部署时更改,默认为主机 OS 设置的任何内容。当 JVM 中任何应用程序的任何线程中的任何代码调用 TimeZone.setDefault 时,它可以在运行时的任何时刻发生变化。所以最好明确分配一个 desired/expected 时区。

java.time

字符串末尾的 Z 是 Zulu 的缩写,表示 UTC。 Instant class 可以直接解析该格式,以 UTC 格式表示时间轴上的一个时刻,分辨率为纳秒。

String input = "2015-06-27T13:16:37.363Z";
Instant instant = Instant.parse( input );

将时区从 UTC 更改为某个 desired/expected 时区。

ZoneID zone = ZoneId.of( "America/Montreal" ) ;
ZonedDateTime zdtMontréal = instant.atZone( zone ) ;

如果您确实需要 java.util.Date 互操作性,请转换。

java.util.Date utilDate = Date.from( zdtMontréal.toInstant() ) ;

Joda-Time

Joda-Time 项目现在处于维护模式,团队建议迁移到 java.time classes:

Note that from Java SE 8 onwards, users are asked to migrate to java.time (JSR-310) - a core part of the JDK which replaces this project.

使用 Joda-Time 2.8.1 的示例代码。

String input = "2015-06-27T13:16:37.363Z" ;
DateTimeZone zone = DateTimeZone.UTC ;  //  Or: DateTimeZone.forID( "America/Montreal" ) ;
DateTime dateTime = new DateTime( input, zone ) ;

如果您确实需要 java.util.Date 互操作性,请转换。

java.util.Date date = dateTime.toDate();

关于java.time

java.time framework is built into Java 8 and later. These classes supplant the troublesome old legacy date-time classes such as java.util.Date, Calendar, & SimpleDateFormat.

要了解更多信息,请参阅 Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310

Joda-Time project, now in maintenance mode, advises migration to the java.time classes.

您可以直接与数据库交换 java.time 对象。使用 JDBC driver compliant with JDBC 4.2 或更高版本。不需要字符串,不需要 java.sql.* classes.

从哪里获得java.time classes?

ThreeTen-Extra project extends java.time with additional classes. This project is a proving ground for possible future additions to java.time. You may find some useful classes here such as Interval, YearWeek, YearQuarter, and more.