java.time.ZonedDateTime.parse和iso8601?

cla*_*lay 9 java iso8601 java-8

为什么JDK8 DateTime库似乎无法解析有效的iso8601日期时间strings?它在时区偏移上窒息,表示为"+01"而不是"+01:00"

这有效:

java.time.ZonedDateTime.parse("2015-08-18T00:00+01:00")
Run Code Online (Sandbox Code Playgroud)

这会抛出一个解析异常:

java.time.ZonedDateTime.parse("2015-08-18T00:00+01")
Run Code Online (Sandbox Code Playgroud)

来自iso8601维基百科页面:

与UTC的偏移量以与"Z"相同的方式附加到时间,格式为±[hh]:[mm],±[hh] [mm]或±[hh].因此,如果描述的时间比UTC早一个小时(例如冬季柏林的时间),则区域指示符将为"+01:00","+ 0100"或简称为"+01".

编辑:这看起来像JDK中的实际合法错误.

https://bugs.openjdk.java.net/browse/JDK-8032051

哇,经过多年测试新的日期时间后,我认为他们会发现一些如此明显的东西.我还认为JDK作者类型非常严格,可以使用更好的自动化测试套件.

更新:这在当前的jdk-9版本中完全修复.我刚刚确认了.上面显示的完全相同的解析命令在当前的jdk-8构建中失败,并且在jdk-9中完美地工作.

附录:FWIW,基于ISO-8601的RFC 3339,不允许这个简写.您必须在时区偏移中指定分钟.

mkc*_*zyk 6

使用此默认格式化程序:ISO_OFFSET_DATE_TIME(因为 parse 2015-08-18T00:00+01:00)。

在文档中:

这将返回一个不可变的格式化程序,能够格式化和解析 ISO-8601 扩展偏移日期时间格式。[...]

偏移量 ID。如果偏移量有秒,那么即使这不是 ISO-8601 标准的一部分,它们也会被处理。解析不区分大小写。

它是(您仅将其用于此默认格式化程序):

ID 是偏移量的标准 ISO-8601 格式字符串的微小变化。有以下三种格式:

  • Z - UTC (ISO-8601)
  • +hh:mm 或 -hh:mm - 如果秒为零 (ISO-8601)
  • +hh:mm:ss 或 -hh:mm:ss - 如果秒非零(不是 ISO-8601)(不+hh喜欢 ISO-8601)。

看来 java.time (JDK 8) 并没有完全实现 ISO-8601。


这:

java.time.ZonedDateTime.parse("2015-08-18T00:00+01:00"); // works
Run Code Online (Sandbox Code Playgroud)

对应于(大致来自 JDK 源代码):

DateTimeFormatterBuilder builder = new DateTimeFormatterBuilder();
DateTimeFormatter formatter = builder
        .parseCaseInsensitive()
        .append(DateTimeFormatter.ISO_LOCAL_DATE_TIME)
        .appendOffsetId()
        .toFormatter();

java.time.ZonedDateTime.parse("2015-08-18T00:00+01:00", formatter); // it's same
Run Code Online (Sandbox Code Playgroud)

您可以使用DateTimeFormatterBuilder创建自己的DataTimeFormatter

DateTimeFormatterBuilder builder2 = new DateTimeFormatterBuilder();
DateTimeFormatter formatter2 = builder2.parseCaseInsensitive()
        .append(DateTimeFormatter.ISO_LOCAL_DATE_TIME)
        .appendPattern("X") // eg.:
        .toFormatter();

java.time.ZonedDateTime.parse("2015-08-18T00:00+01", formatter2); // here you set +01
Run Code Online (Sandbox Code Playgroud)

使用appendPattern(字符串模式)代替appendOffsetId()并设置'X'或'x'。

现在,您可以使用您的 datatime 2015-08-18T00:00+01


或者...使用默认 ISO_OFFSET_DATE_TIME 并添加 postfix :00

java.time.ZonedDateTime.parse("2015-08-18T00:00+01" + ":00");
Run Code Online (Sandbox Code Playgroud)

但这最后一个解决方案很糟糕。


cla*_*lay 1

这在当前的 jdk-9 版本中已完全修复。我刚刚确认。上面显示的完全相同的解析命令在当前的 jdk-8 构建中失败,但在 jdk-9 中完美运行。

\n\n

使用新的 jdk-9 shell:

\n\n
\xe2\x9e\x9c  jdk-9 bin/jshell\n|  Welcome to JShell -- Version 9-ea\n|  For an introduction type: /help intro\n\njshell> java.time.ZonedDateTime.parse("2015-08-18T00:00+01")\n$1 ==> 2015-08-18T00:00+01:00\n
Run Code Online (Sandbox Code Playgroud)\n