时区不是一个固定的偏移。这篇直接读 ZoneRules,看夏令时的空洞和重叠、一天的长度、历史上的偏移、未来时间如何推算,以及 ZoneId.of 的边界。
[gap]
2026-06-01T12:00 的有效偏移:[-04:00];getTransition = null
2026-03-08T02:30 的有效偏移:[];getTransition = Transition[Gap at 2026-03-08T02:00-05:00 to -04:00]
2026-11-01T01:30 的有效偏移:[-04:00, -05:00];getTransition = Transition[Overlap at 2026-11-01T02:00-04:00 to -05:00]
ZonedDateTime.of(gap) → 2026-03-08T03:30-04:00[America/New_York](落在空洞里的时间被顺延)
ZonedDateTime.of(overlap) → 2026-11-01T01:30-04:00[America/New_York](默认取较早的偏移)
.withLaterOffsetAtOverlap() → 2026-11-01T01:30-05:00[America/New_York];两者相差 PT1H
OffsetDateTime 的偏移要自己给:LocalDateTime.of(gap).atOffset(-05:00) → 2026-03-08T02:30-05:00(这个本地时间在纽约并不存在,API 不报错) [daylen]
2026-03-07 在 New_York 有 24 小时(atStartOfDay 2026-03-07T00:00-05:00[America/New_York])
2026-03-08 在 New_York 有 23 小时(atStartOfDay 2026-03-08T00:00-05:00[America/New_York])
2026-11-01 在 New_York 有 25 小时(atStartOfDay 2026-11-01T00:00-04:00[America/New_York])
2026-11-02 在 New_York 有 24 小时(atStartOfDay 2026-11-02T00:00-05:00[America/New_York])
2026-03-07T12:00 纽约:plusDays(1) = 2026-03-08T12:00-04:00[America/New_York];plus(Duration.ofHours(24)) = 2026-03-08T13:00-04:00[America/New_York]
Period.ofDays(1) 与 Duration.ofDays(1) 在 ZonedDateTime 上:12:00 vs 13:00
同一天在 Asia/Shanghai(2026-03-08):24 小时 [history]
Asia/Shanghai isFixedOffset = false;ZoneOffset.ofHours(8) 的规则 isFixedOffset = true
1850-01-01T00:00:00Z → 偏移 +08:05:43 夏令时偏移量 PT0S
1901-01-01T00:00:00Z → 偏移 +08:00 夏令时偏移量 PT0S
1940-07-01T00:00:00Z → 偏移 +09:00 夏令时偏移量 PT1H
1988-07-01T00:00:00Z → 偏移 +09:00 夏令时偏移量 PT1H
1992-07-01T00:00:00Z → 偏移 +08:00 夏令时偏移量 PT0S
2026-07-01T00:00:00Z → 偏移 +08:00 夏令时偏移量 PT0S
Asia/Shanghai 的显式转换共 29 条;最早 Transition[Overlap at 1901-01-01T00:00+08:05:43 to +08:00];最晚 Transition[Overlap at 1991-09-15T02:00+09:00 to +08:00]
1988 夏令时开始与结束:[Transition[Gap at 1988-04-17T02:00+08:00 to +09:00], Transition[Overlap at 1988-09-11T02:00+09:00 to +08:00]]
Europe/London 1970-07-01 的偏移 = +01:00(1968–1971 全年夏令时);1970-01-01 = +01:00 [future]
New_York 显式转换 177 条,最晚一条在 2008-11-02T02:00;重复规则 2 条:
TransitionRule[Gap -05:00 to -04:00, SUNDAY on or after MARCH 8 at 02:00 WALL, standard offset -05:00]
TransitionRule[Overlap -04:00 to -05:00, SUNDAY on or after NOVEMBER 1 at 02:00 WALL, standard offset -05:00]
2026-07-01 偏移 -04:00;该年下一次转换 Transition[Overlap at 2026-11-01T02:00-04:00 to -05:00]
2100-07-01 偏移 -04:00;该年下一次转换 Transition[Overlap at 2100-11-07T02:00-04:00 to -05:00]
3000-07-01 偏移 -04:00;该年下一次转换 Transition[Overlap at 3000-11-02T02:00-04:00 to -05:00]
2100 年之后的第一次转换:2100-03-14T03:00
Asia/Shanghai 显式转换 29 条,重复规则 0 条,最晚的显式转换 1991-09-14T17:00:00Z
Asia/Tokyo 显式转换 9 条,重复规则 0 条,最晚的显式转换 1951-09-08T15:00:00Z
Europe/Paris 显式转换 102 条,重复规则 2 条,最晚的显式转换 1997-10-26T01:00:00Z
Australia/Sydney 显式转换 86 条,重复规则 2 条,最晚的显式转换 2009-10-03T16:00:00Z
Africa/Casablanca 显式转换 196 条,重复规则 0 条,最晚的显式转换 2087-05-11T02:00:00Z
America/Sao_Paulo 显式转换 91 条,重复规则 0 条,最晚的显式转换 2019-02-17T02:00:00Z
Asia/Kolkata 显式转换 7 条,重复规则 0 条,最晚的显式转换 1945-10-14T17:30:00Z [JDK 17]
JDK 17.0.20.1;tzdata 版本(Asia/Shanghai)= [2026b];可用 ZoneId 数 604
Asia/Almaty 2024-06-01 偏移 +05:00 2026-07-01 偏移 +05:00 夏令时=false
America/Mexico_City 2024-06-01 偏移 -06:00 2026-07-01 偏移 -06:00 夏令时=false
America/Ciudad_Juarez 2024-06-01 偏移 -06:00 2026-07-01 偏移 -06:00 夏令时=true
Europe/Kyiv 2024-06-01 偏移 +03:00 2026-07-01 偏移 +03:00 夏令时=true
Europe/Kiev 2024-06-01 偏移 +03:00 2026-07-01 偏移 +03:00 夏令时=true
Asia/Yangon 2024-06-01 偏移 +06:30 2026-07-01 偏移 +06:30 夏令时=false
Mexico_City 2022-07-01 偏移 -05:00;2023-07-01 偏移 -06:00
Almaty 2024-02-28 偏移 +06:00;2024-03-02 偏移 +05:00
[JDK 21]
JDK 21.0.12.1;tzdata 版本(Asia/Shanghai)= [2026b];可用 ZoneId 数 604
Asia/Almaty 2024-06-01 偏移 +05:00 2026-07-01 偏移 +05:00 夏令时=false
America/Mexico_City 2024-06-01 偏移 -06:00 2026-07-01 偏移 -06:00 夏令时=false
America/Ciudad_Juarez 2024-06-01 偏移 -06:00 2026-07-01 偏移 -06:00 夏令时=true
Europe/Kyiv 2024-06-01 偏移 +03:00 2026-07-01 偏移 +03:00 夏令时=true
Europe/Kiev 2024-06-01 偏移 +03:00 2026-07-01 偏移 +03:00 夏令时=true
Asia/Yangon 2024-06-01 偏移 +06:30 2026-07-01 偏移 +06:30 夏令时=false
Mexico_City 2022-07-01 偏移 -05:00;2023-07-01 偏移 -06:00
Almaty 2024-02-28 偏移 +06:00;2024-03-02 偏移 +05:00
[JDK 27]
JDK 27;tzdata 版本(Asia/Shanghai)= [2026b];可用 ZoneId 数 604
Asia/Almaty 2024-06-01 偏移 +05:00 2026-07-01 偏移 +05:00 夏令时=false
America/Mexico_City 2024-06-01 偏移 -06:00 2026-07-01 偏移 -06:00 夏令时=false
America/Ciudad_Juarez 2024-06-01 偏移 -06:00 2026-07-01 偏移 -06:00 夏令时=true
Europe/Kyiv 2024-06-01 偏移 +03:00 2026-07-01 偏移 +03:00 夏令时=true
Europe/Kiev 2024-06-01 偏移 +03:00 2026-07-01 偏移 +03:00 夏令时=true
Asia/Yangon 2024-06-01 偏移 +06:30 2026-07-01 偏移 +06:30 夏令时=false
Mexico_City 2022-07-01 偏移 -05:00;2023-07-01 偏移 -06:00
Almaty 2024-02-28 偏移 +06:00;2024-03-02 偏移 +05:00 [ids]
ZoneId.of("EST" ) → ZoneRulesException: Unknown time-zone ID: EST
ZoneId.of("PST" ) → ZoneRulesException: Unknown time-zone ID: PST
ZoneId.of("Asia/Calcutta" ) → Asia/Calcutta ZoneRegion
ZoneId.of("Asia/Kolkata" ) → Asia/Kolkata ZoneRegion
ZoneId.of("GMT+8" ) → GMT+08:00 ZoneRegion
ZoneId.of("UTC+08:00" ) → UTC+08:00 ZoneRegion
ZoneId.of("UTC" ) → UTC ZoneRegion
ZoneId.of("Z" ) → Z ZoneOffset
ZoneId.of("+08" ) → +08:00 ZoneOffset
ZoneId.of("Asia/Shangai" ) → ZoneRulesException: Unknown time-zone ID: Asia/Shangai
ZoneId.of("asia/shanghai" ) → ZoneRulesException: Unknown time-zone ID: asia/shanghai
ZoneId.of("America/New_York ") → DateTimeException: Invalid ID for region-based ZoneId, invalid format: America/New_York
ZoneId.of("EST", ZoneId.SHORT_IDS) = -05:00;PST → America/Los_Angeles;CST → America/Chicago;IST → Asia/Kolkata
Asia/Calcutta 与 Asia/Kolkata 是否 equals:false;规则对象是否相同:true