我正在将应用程序从jdk 8迁移到11,我可以看到ZonedDateTime更改是关于夏时制的行为。 JDK8
ZonedDateTime parse = ZonedDateTime.parse("2037-05-10T19:15:00.000+01:00[Europe/Paris]");
System.out.println(parse);
输出: 2037-05-10T19:15 + 02:00 [欧洲/巴黎]
JDK11 / 12
ZonedDateTime parse = ZonedDateTime.parse("2037-05-10T19:15:00.000+01:00[Europe/Paris]");
System.out.println(parse);
2037-05-10T20:15 + 02:00 [欧洲/巴黎]
有人可以向我解释为什么他们会改变这种行为吗?
最诚挚的问候,
答案 0 :(得分:6)
我相信您在Java 8中遇到的实际上是以下错误:ZonedDateTime.parse() returns wrong ZoneOffset around DST fall transition。错误标题并不能说明全部情况。真正的问题是,在Java 8 DateTimeFormatter.ISO_ZONED_DATE_TIME
(您所使用的一个参数ZonedDateTime.parse
隐式使用)中,如果解析的字符串中包含时区ID,则会忽略偏移量。结合时区数据库,该数据库与您的有关字符串的偏移量在2037年10月巴黎所使用的偏移量不一致的情况下,将导致解析时间与该字符串中的偏移量发生冲突。
该错误已在Java 9中修复。因此,在Java 9、10和11中,由于仍然存在关于offset的相同分歧,因此,解析时刻基于字符串的offset。然后使用时区数据库中的规则将其从字符串转换为时区。这将使偏移量从+01:00更改为+02:00,并且将一天中的时间从19:15更改为20:15。我同意Java 9+,这是正确的行为。
您的问题也部分由将来使用ZonedDateTime
引起。仅在不久的将来(我们假设没有更改区域规则)才建议这样做。对于2037年的日期和时间,如果您知道时刻,则应该使用Instant
,或者如果您只知道日期和时间,则应该使用LocalDateTime
。仅当时间临近并且您相信Java安装已更新了最新的时区时,才转换为ZonedDateTime
。
正如评论中所讨论的那样,我们可能尚不知道2037年10月巴黎的正确UTC偏移量。欧盟似乎有可能从2021年开始放弃夏令时(DST),据我所知,法国政客尚未决定此后的法国时间。
要从字符串(19:15)中获取时间,请解析为LocalDateTime
:
String zdtString = "2037-05-10T19:15:00.000+01:00[Europe/Paris]";
LocalDateTime dateTime
= LocalDateTime.parse(zdtString, DateTimeFormatter.ISO_ZONED_DATE_TIME);
System.out.println("Date and time from string: " + dateTime);
输出为(在Java 11上运行):
日期和时间从字符串:2037-05-10T19:15
如果您希望在更高的Java版本上拥有完整的Java 8行为-如我所提到的,不建议这样做,则不应在此处使用ZonedDateTime
:
TemporalAccessor parsed = DateTimeFormatter.ISO_ZONED_DATE_TIME.parse(zdtString);
LocalDateTime dateTime = LocalDateTime.from(parsed);
ZoneId zone = ZoneId.from(parsed);
ZonedDateTime java8Zdt = dateTime.atZone(zone);
System.out.println("Time from string in zone from string: " + java8Zdt);
字符串中的时间,字符串中的区域:2037-05-10T19:15 + 02:00 [欧洲/巴黎]