java.time.ZonedDateTime.parse 和 iso8601?
java.time.ZonedDateTime.parse and 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.
中完美运行
ADDENDUM:FWIW,基于 ISO-8601 的 RFC 3339,不允许这种简写。您必须在时区偏移量中指定分钟数。
使用的代码由 DateTimeFormatterBuilder.appendZoneId() 添加,允许时区格式为
For example, the following will parse:
"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
你use this default formatter: 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
您可以创建自己的DataTimeFormatter with DateTimeFormatterBuilder。
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");
但最后这个解决方案很糟糕。
这在当前的 jdk-9 版本中已完全修复。我刚刚确认。上面显示的完全相同的解析命令在当前 jdk-8 构建中失败,但在 jdk-9.
中完美运行
使用新的 jdk-9 shell:
➜ jdk-9 bin/jshell
| Welcome to JShell -- Version 9-ea
| For an introduction type: /help intro
jshell> java.time.ZonedDateTime.parse("2015-08-18T00:00+01")
==> 2015-08-18T00:00+01:00
谢谢@mkczyk 说我为这项工作制作了自己的格式化程序。
我需要一个日期解析器,比如
- “2016-02-14T18:32:04.150Z”
- "2016-02-14T21:32:04.150+04"
- "2016-02-14T21:32:04.150+04:00"
private static final DateTimeFormatter DATE_TIME_NANOSECONDS_OFFSET_FORMATTER =
new DateTimeFormatterBuilder().parseCaseInsensitive().append(ISO_LOCAL_DATE_TIME)
.appendFraction(ChronoField.NANO_OF_SECOND, 0, 3, true)
.appendOffset("+HH:mm", "Z")
.toFormatter();
appendfraction(..,..,..,true) 将纳秒视为秒的小数点。
ZonedDateTime zdt = ZonedDateTime.parse(textToParse, DATE_TIME_NANOSECONDS_OFFSET_FORMATTER);
之后用于从中获取 UTC 时间。
zdt = ZonedDateTime.ofInstant(zdt.toInstant(), ZoneId.of("UTC"));
为什么 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.
中完美运行ADDENDUM:FWIW,基于 ISO-8601 的 RFC 3339,不允许这种简写。您必须在时区偏移量中指定分钟数。
使用的代码由 DateTimeFormatterBuilder.appendZoneId() 添加,允许时区格式为
For example, the following will parse:
"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
你use this default formatter: 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
您可以创建自己的DataTimeFormatter with DateTimeFormatterBuilder。
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");
但最后这个解决方案很糟糕。
这在当前的 jdk-9 版本中已完全修复。我刚刚确认。上面显示的完全相同的解析命令在当前 jdk-8 构建中失败,但在 jdk-9.
中完美运行使用新的 jdk-9 shell:
➜ jdk-9 bin/jshell
| Welcome to JShell -- Version 9-ea
| For an introduction type: /help intro
jshell> java.time.ZonedDateTime.parse("2015-08-18T00:00+01")
==> 2015-08-18T00:00+01:00
谢谢@mkczyk 说我为这项工作制作了自己的格式化程序。 我需要一个日期解析器,比如
- “2016-02-14T18:32:04.150Z”
- "2016-02-14T21:32:04.150+04"
- "2016-02-14T21:32:04.150+04:00"
private static final DateTimeFormatter DATE_TIME_NANOSECONDS_OFFSET_FORMATTER =
new DateTimeFormatterBuilder().parseCaseInsensitive().append(ISO_LOCAL_DATE_TIME)
.appendFraction(ChronoField.NANO_OF_SECOND, 0, 3, true)
.appendOffset("+HH:mm", "Z")
.toFormatter();
appendfraction(..,..,..,true) 将纳秒视为秒的小数点。
ZonedDateTime zdt = ZonedDateTime.parse(textToParse, DATE_TIME_NANOSECONDS_OFFSET_FORMATTER);
之后用于从中获取 UTC 时间。
zdt = ZonedDateTime.ofInstant(zdt.toInstant(), ZoneId.of("UTC"));