java.time.ZonedDateTime.parse 和 iso8601?

标签 java java-8 iso8601

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

这个有效:

java.time.ZonedDateTime.parse("2015-08-18T00:00+01:00")

这会抛出一个解析异常:

java.time.ZonedDateTime.parse("2015-08-18T00:00+01")

来自 iso8601 维基百科页面:

The offset from UTC is appended to the time in the same way that 'Z' was above, in the form ±[hh]:[mm], ±[hh][mm], or ±[hh]. So if the time being described is one hour ahead of UTC (such as the time in Berlin during the winter), the zone designator would be "+01:00", "+0100", or simply "+01".

编辑:这看起来像是 JDK 中真正合法的错误。

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

哇,在测试新的日期时间东西多年之后,我认为他们会发现如此明显的东西。我还认为 JDK 作者类型足够严格,可以使用更好的自动化测试套件。

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

附录:FWIW,基于 ISO-8601 的 RFC 3339,不允许使用这种缩写形式。您必须在时区偏移量中指定分钟数。

最佳答案

use此默认格式化程序:ISO_OFFSET_DATE_TIME (因为解析 2015-08-18T00:00+01:00)。

在文档中:

This returns an immutable formatter capable of formatting and parsing the ISO-8601 extended offset date-time format. [...]

The offset ID. If the offset has seconds then they will be handled even though this is not part of the ISO-8601 standard. Parsing is case insensitive.

It's (您仅将此用于此默认格式化程序):

The ID is minor variation to the standard ISO-8601 formatted string for the offset. There are three formats:

  • Z - for UTC (ISO-8601)
  • +hh:mm or -hh:mm - if the seconds are zero (ISO-8601)
  • +hh:mm:ss or -hh:mm:ss - if the seconds are non-zero (not ISO-8601) (don't +hh like ISO-8601).

似乎 java.time (JDK 8) 没有完全实现 ISO-8601。


这个:

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

对应于(大致来自源 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

您可以创建自己的 DataTimeFormatterDateTimeFormatterBuilder .

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

代替 appendOffsetId() 使用 appendPattern(String pattern)并设置 'X' 或 'x'。

现在,您可以使用数据时间 2015-08-18T00:00+01


或者...使用默认的 ISO_OFFSET_DATE_TIME 并添加后缀 :00

java.time.ZonedDateTime.parse("2015-08-18T00:00+01" + ":00");

但最后一个是糟糕的解决方案。

关于java.time.ZonedDateTime.parse 和 iso8601?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32079459/

相关文章:

java - 如何保存我的 Android 应用程序,以便最终用户无需 Android SDK 即可执行它

java - 二维数组中缺少数组检查 - Java

java - MySQLIntegrityConstraintViolationException : Cannot add or update a child row: a foreign key constraint fails

Java 8 和流上的聚合操作

java - 使用 jquery 将 UTF-8 字符串发布到 servlet

java - JDK8与Windows XP兼容吗?

Java 8 过滤和收集 List<Map<String, Object>>

c# - 反序列化 iso 8601 日期

datetime - ISO 8601 夏令时

javascript - 基于 navigator.language 将 ISO 8601 日期字符串显示为本地日期和时间