Java ZoneID是否保证解析以前存在的时区?

huangapple go评论111阅读模式
英文:

Is Java ZoneID guaranteed to parse previously existing timezones?

问题

在2022年底,IANA 将时区 Europe/Kiev 重命名为 Europe/Kyiv

考虑以下程序:

import java.time.ZoneId;

public class TZPlay {
  public static void main(String[] args) {
    try {
//      ZoneId.of("Europe/Kiev"); // 在Java 17.06和Java 17.03中有效
//      ZoneId.of("Europe/Kyiv"); // 仅在Java 17.06中有效,而不在Java 17.03中有效
    } catch (Exception e) {
      e.printStackTrace();
    }
  }
}

观察:

  • 在尝试解析 Europe/Kyiv 时,Java 17.03 抛出以下异常。
java.time.zone.ZoneRulesException: 未知的时区 ID: Europe/Kyiv
        at java.base/java.time.zone.ZoneRulesProvider.getProvider(ZoneRulesProvider.java:280)
        at java.base/java.time.zone.ZoneRulesProvider.getRules(ZoneRulesProvider.java:235)
        at java.base/java.time.ZoneRegion.ofId(ZoneRegion.java:121)
        at java.base/java.time.ZoneId.of(ZoneId.java:410)
        at java.base/java.time.ZoneId.of(ZoneId.java:358)
        at TZPlay.main(TZPlay.java:7)
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
        at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.base/java.lang.reflect.Method.invoke(Method.java:568)
        at jdk.compiler/com.sun.tools.javac.launcher.Main.execute(Main.java:419)
        at jdk.compiler/com.sun.tools.javac.launcher.Main.run(Main.java:192)
        at jdk.compiler/com.sun.tools.javac.launcher.Main.main(Main.java:132)
  • Java 17.06 在不抛出异常的情况下正确解析它。
  • 此外,Java 17.06 也在不抛出异常的情况下解析 Europe/Kiev

根据上面的示例,经验上似乎较新版本的Java能够在时区重命名后解析较旧的时区。

这是否保证总是成立,或者旧时区有时会在较新的Java小版本上出现问题?

我在 ZoneId javadoc 中搜索了 "previous"、"old" 和 "rename" 这些词汇,但没有找到明显的信息。

英文:

In late 2022, the timezone Europe/Kiev was renamed to Europe/Kyiv by IANA.

Consider the following program:

import java.time.ZoneId;
public class TZPlay {
public static void main(String[] args) {
try {
//      ZoneId.of("Europe/Kiev"); // Works in Java 17.06 and Java 17.03
//      ZoneId.of("Europe/Kyiv"); // Works in Java 17.06 but not Java 17.03.
} catch (Exception e) {
e.printStackTrace();
}
}
}

Observations:

  • Java 17.03 throws the following exception when trying to parse Europe/Kyiv.
java.time.zone.ZoneRulesException: Unknown time-zone ID: Europe/Kyiv
at java.base/java.time.zone.ZoneRulesProvider.getProvider(ZoneRulesProvider.java:280)
at java.base/java.time.zone.ZoneRulesProvider.getRules(ZoneRulesProvider.java:235)
at java.base/java.time.ZoneRegion.ofId(ZoneRegion.java:121)
at java.base/java.time.ZoneId.of(ZoneId.java:410)
at java.base/java.time.ZoneId.of(ZoneId.java:358)
at TZPlay.main(TZPlay.java:7)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:568)
at jdk.compiler/com.sun.tools.javac.launcher.Main.execute(Main.java:419)
at jdk.compiler/com.sun.tools.javac.launcher.Main.run(Main.java:192)
at jdk.compiler/com.sun.tools.javac.launcher.Main.main(Main.java:132)
  • Java 17.06 correctly parses it without exception.
  • Moreover, Java 17.06 also parses Europe/Kiev without exception.

Empirically, based on the above example, it seems like newer versions of Java are able to parse older timezones after they were renamed.

Is this guaranteed to always be true, or will old timezones sometimes break on newer Java minor versions?

I searched the ZoneId javadoc for the terms "previous", "old" and "rename" but did not find anything obvious.

答案1

得分: 2

这不是绝对保证的。Java 使用Common Locale Data Repository中的数据,它们会定期更新。

已经发生过更新导致破坏性更改的情况,例如:这里

那个时区恰好有这两个示例作为有效的别名。请参考:这里 ,但没有要求它们这样做。

时区名称不是您应该期望向前兼容的东西。这些数据模拟了真实世界,而真实世界不断变化。如果您想要依赖未来可靠性的内容,那么请使用偏移,即 +02:00

英文:

It's not guaranteed. Java uses data from Common Locale Data Repository and they periodically update it.

There have been cases where that update was a breaking change, e.g. this: https://stackoverflow.com/questions/69267710/septembers-short-form-sep-no-longer-parses-in-java-17-in-en-gb-locale

That zone just happens to have both of those examples as valid aliases. See: https://github.com/openjdk/jdk/blob/master/make/data/cldr/common/bcp47/timezone.xml#L398 but there is no requirement that they do so.

A zone name is not really something you should expect forwards compatibility for. This data models the real world, and the real world is constantly changing. If you want to rely on something that's future-proof, then use the offset, i.e. +02:00.

huangapple
  • 本文由 发表于 2023年3月7日 06:58:12
  • 转载请务必保留本文链接:https://go.coder-hub.com/75656590.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定