英文:
Historic timezone offsets in newer JDK versions
问题
我在测试一些时区时,发现了一个奇怪的Java差异,使用ZonedDateTime
。我试图解析1970年之前的日期,发现结果在不同的Java版本之间会发生变化。1932年荷兰的偏移是+00:19
。有人知道为什么会发生这种情况吗?我觉得这可能与时区数据库项目(https://github.com/eggert/tz)中欧洲时区的捆绑有关,但我不确定。是否有办法在Java中获得旧的行为?比如通过设置?
ZonedDateTime zdt = LocalDateTime.parse("1932-10-20T10:19:32.000").atZone(ZoneId.of("Europe/Amsterdam"));
System.out.println(zdt);
DateTimeFormatter formatter = new DateTimeFormatterBuilder()
.append(ISO_LOCAL_DATE)
.appendLiteral('T')
.appendValue(HOUR_OF_DAY, 2)
.appendLiteral(':')
.appendValue(MINUTE_OF_HOUR, 2)
.optionalStart()
.appendLiteral(':')
.appendValue(SECOND_OF_MINUTE, 2)
.optionalStart()
.appendFraction(NANO_OF_SECOND, 3, 3, true)
.appendOffset("+HH:MM", "Z")
.toFormatter();
System.println(formatter.format(zdt));
System.out.println(
java.time.zone.ZoneRulesProvider
.getVersions("UTC")
.lastEntry()
.getKey()
);
在Temurin(Java JDK)11.0.16中的结果(期望输出),最后一行显示时区数据库版本:
1932-10-20T10:19:32+00:19:32[Europe/Amsterdam]
1932-10-20T10:19:32.000+00:19
2022a
在Temurin 11.0.17中的结果:
1932-10-20T10:19:32Z[Europe/Amsterdam]
1932-10-20T10:19:32.000Z
2022c
编辑:JDK 17中也存在问题,从17.0.5版本开始:
Temurin 17.0.4:
1932-10-20T10:19:32+00:19:32[Europe/Amsterdam]
1932-10-20T10:19:32.000+00:19
2022a
Temurin 17.0.5:
1932-10-20T10:19:32Z[Europe/Amsterdam]
1932-10-20T10:19:32.000Z
2022c
英文:
I found a weird java discrepancy while testing some timezones with the use of ZonedDateTime
. I was trying to parse a date before 1970 and saw that the result changes between java versions. The offset for Netherlands in 1932 is +00:19
. Does anyone know why this happens? I feel this might be related with the bundling of european timezones in the time zone database project (https://github.com/eggert/tz), but i'm not sure. Is there a way to get the old behavior in java? Like with a setting?
ZonedDateTime zdt = LocalDateTime.parse("1932-10-20T10:19:32.000").atZone(ZoneId.of("Europe/Amsterdam"));
System.out.println(zdt);
DateTimeFormatter formatter = new DateTimeFormatterBuilder()
.append(ISO_LOCAL_DATE)
.appendLiteral('T')
.appendValue(HOUR_OF_DAY, 2)
.appendLiteral(':')
.appendValue(MINUTE_OF_HOUR, 2)
.optionalStart()
.appendLiteral(':')
.appendValue(SECOND_OF_MINUTE, 2)
.optionalStart()
.appendFraction(NANO_OF_SECOND, 3, 3, true)
.appendOffset("+HH:MM", "Z")
.toFormatter();
System.out.println(formatter.format(zdt));
System.out.println(
java.time.zone.ZoneRulesProvider
.getVersions("UTC")
.lastEntry()
.getKey()
);
Result in Temurin (java jdk) 11.0.16 (expected output), last line showing timezone database version:
1932-10-20T10:19:32+00:19:32[Europe/Amsterdam]
1932-10-20T10:19:32.000+00:19
2022a
Result in Temurin 11.0.17:
1932-10-20T10:19:32Z[Europe/Amsterdam]
1932-10-20T10:19:32.000Z
2022c
Edit: Also an issue in JDK 17 starting from 17.0.5:
Temurin 17.0.4:
1932-10-20T10:19:32+00:19:32[Europe/Amsterdam]
1932-10-20T10:19:32.000+00:19
2022a
Temurin 17.0.5:
1932-10-20T10:19:32Z[Europe/Amsterdam]
1932-10-20T10:19:32.000Z
2022c
答案1
得分: 17
免责声明:我是 OP 的同事。这个问题让办公室里一半的人都感到困惑。
在 @Sweeper 的评论帮助下,我认为我们已经找到了原因。
背景
2022年,受到 Timezone Database 的启发,他们进行了一些整理工作,并在版本2022b
的backzone
文件中存档了大量1970年以前的时区数据。这使他们能够合并,例如,在较新的1970年以后的数据库中合并了Europe/Brussels
和Europe/Amsterdam
(因为在1970年之后,这些实际上是相等的)。
他们还引入了一个特殊选项(PACKRATLIST
)来构建包含历史时区数据的时区数据库。
OpenJDK 更新到了 Timezone Database 的新版本,但选择使用了没有历史数据的版本,随后一些开发者注意到了一些问题。
然而,相关的 OpenJDK bug 目前列出了支持backzone
的问题为“不会修复”。
受影响的 JDK 版本
- 从11.0.17版本开始的 Java 11。
- 从17.0.5版本开始的 Java 17。
可能的解决方案
- 也许更新的 JDK 版本最终会修复这个问题?此刻还不清楚。
- 或者,使用更新的 JDK 版本,但采用这个解决方法,安装一个旧版本(
2022a
)的 Timezone Database。 - 或者,重写依赖于这些历史数据的所有代码,可能需要硬编码相关的时区偏移值,如果这是一个有限的集合。
英文:
Disclaimer: I'm a colleague of OP. This issue has half the office baffled.
Helped along by comments by @Sweeper below the question, I think we've found the cause.
Background
The venerable Timezone Database did some housecleaning in 2022, and archived a lot of pre-1970 timezone data in their backzone
file for version 2022b
. This allowed them to merge, for example, Europe/Brussels
and Europe/Amsterdam
in the leaner post-1970 database (because after 1970, these are in fact equal).
They also introduced a special option (PACKRATLIST
) for building the timezone database with the historic timezones intact.
OpenJDK updated to the new version of the Timezone Database, but chose to use the version without historical data, and subsequently, some developers noticed things breaking.
The relevant OpenJDK bug however currently lists supporting the backzone
as won't fix.
Affected JDK's
- Java 11 from 11.0.17 onwards.
- Java 17 from 17.0.5 onwards.
Possible solutions
- Perhaps newer JDK's will fix this after all? Unknown at this moment.
- Alternatively, use the newer JDK's, but apply this workaround to install an older version (
2022a
) of the Timezone Database instead. - Or, rewrite all code that depends on this historical data, possibly by hardcoding the relevant timezone offsets if it is a limited set.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论