java.time.ZonedDateTime.parse 和 iso8601?

2022-09-04 22:43:58

为什么 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维基百科页面:

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

编辑:这看起来像是JDK中一个实际的合法错误。

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

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

更新:这在当前的jdk-9版本中完全修复。我刚刚确认了。上面显示的完全相同的 parse 命令在当前的 jdk-8 版本中失败,并且在 jdk-9 中运行良好。

附录:FWIW,RFC 3339 基于 ISO-8601,不允许使用此简写。必须在时区偏移量中指定分钟数。


答案 1

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

在文档中:

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

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

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

ID 与偏移量的标准 ISO-8601 格式字符串相比略有不同。有三种格式:

  • Z - 代表世界标准时间 (ISO-8601)
  • +hh:mm 或 -hh:mm - 如果秒数为零 (ISO-8601)
  • +hh:mm:ss 或 -hh:mm:ss - 如果秒数不为零(不是 ISO-8601)(不喜欢 ISO-8601)。+hh

似乎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

您可以使用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

不要使用 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");

但最后一个是不好的解决方案。


答案 2

使用的代码由DateTimeFormatterBuilder.appendZoneId()添加,它允许时区的格式为

例如,以下内容将进行解析:

"Europe/London"           -- ZoneId.of("Europe/London")
"Z"                       -- ZoneOffset.UTC
"UT"                      -- ZoneId.of("UT")
"UTC"                     -- ZoneId.of("UTC")
"GMT"                     -- ZoneId.of("GMT")
"+01:30"                  -- ZoneOffset.of("+01:30")
"UT+01:30"                -- ZoneOffset.of("+01:30")
"UTC+01:30"               -- ZoneOffset.of("+01:30")
"GMT+01:30"               -- ZoneOffset.of("+01:30")

您可以定义自己的日期时间格式以允许小时偏移,但世界上许多地方都有一小时的分数,例如尼泊尔(+05:45)和朝鲜(最近更改为+08:30)


推荐