java.time.ZoneId 不包括 ZoneIds 的枚举是有原因的吗?

Is there a reason for java.time.ZoneId not including an Enum of ZoneIds?

要获得 ZoneId,它是这样的:

ZoneId.of("America/Sao_Paulo");

ZoneId.of(ZoneId.SHORT_IDS.get("BET"));

为什么不存在 Enum 这样的值,例如:

ZoneId.of(ZoneIds.AMERICA_SAO_PAULO);

哪个看起来不太容易出错并且对自动完成更友好?

如果你看到ZoneId#getAvailableZoneIds方法的描述,那么你知道为什么吗?

This set includes the string form of all available region-based IDs. Offset-based zone IDs are not included in the returned set. The ID can be passed to of(String) to create a ZoneId.

The set of zone IDs can increase over time, although in a typical application the set of IDs is fixed. Each call to this method is thread-safe.

我相信这是因为所有可能的时区名称列表都可以更改,无论 Java 版本如何。

时区信息comes with Java installation (usually in the folder <java-home>/lib/zi, or in jre/lib/tzdb.dat file in newer versions). But this information can be updated without changing the Java version (using the Timezone Updater Tool).

如果更新时区数据(但 Java 版本保持不变)并创建新的时区 ID,则不会有等效的 Enum,留下 API "incomplete"。和时区数据 changes faster than JDK updates - 即使没有,也不总是可以在生产环境中尽快更新 JDK 版本。

我不能代表 API 的创建者,但我认为他们决定保持原样,因为命名空间的增长速度可以快于 JDK 的更新速度,并且维护枚举更新将是一项无休止且总是不完整的工作。

如果你真的想检查时区名称是否有效,你可以这样做:

if (ZoneId.getAvailableZoneIds().contains("America/Sao_Paulo")) {
    // America/Sao_Paulo is a valid ID
}

或者直接调用 ZoneId.of("zone-name") 并捕获 ZoneRulesException


我刚刚在 JDK 1.8.0_131 中调用了 ZoneId.getAvailableZoneIds(),它有 600 个条目。可能没有人想创建 600 个枚举常量。

有人可能会争辩说他们可以做类似于 java.util.Locale class 的事情,其中​​有一些针对某些语言(如英语、德语、法语等)的条目。但是如何决定哪个时区"deserve"是一个常量呢?也许他们只是决定不考虑太多 "hey, forget it, just use a String with the zone name".


另一个可能的原因是 ZoneId.of() 方法被设计为也接收 UTC 偏移量(例如 +05:00-0300+09:30:15 等) .由于偏移量接受小时、分钟和秒,因此有数百种可能的偏移量,为每个偏移量创建枚举是不切实际的。

同样,有人可能会争论 "Hey, create just the enums for the names and forget about the offsets"。但是不创建枚举名称的可能原因已经在上面讨论过。

JDK 中的时区集可以是 completely replaced。 因此,无法为区域定义 enum

另外,时区标识比较不稳定。它们被重命名、合并并且通常被更改。 (包括我在内的各种人都试图让IANA数据库更加稳定,但是数据库维护者不同意。)

将考虑在 ThreeTen-Extra 中创建 ZoneIds class 并提供常量的拉取请求。