LocalDateTime、Instant、ZoneId 到底有什么区别?夏令时会让哪些直觉失效?这篇用真实的时区数据一项项打印出来(ZoneRules 的细节在后面的篇目)。
Instant.ofEpochSecond(1700000000, 123000000) = 2023-11-14T22:13:20.123Z(getEpochSecond = 1700000000,getNano = 123000000)
同一个 LocalDateTime 2024-05-01T09:30 放进不同时区得到不同的瞬间:
UTC → 2024-05-01T09:30Z[UTC],Instant = 2024-05-01T09:30:00Z,偏移 Z
Asia/Shanghai → 2024-05-01T09:30+08:00[Asia/Shanghai],Instant = 2024-05-01T01:30:00Z,偏移 +08:00
America/New_York → 2024-05-01T09:30-04:00[America/New_York],Instant = 2024-05-01T13:30:00Z,偏移 -04:00
Asia/Kolkata → 2024-05-01T09:30+05:30[Asia/Kolkata],Instant = 2024-05-01T04:00:00Z,偏移 +05:30
同一个 Instant 2024-05-01T01:30:00Z 在不同时区的本地时间:
UTC → 2024-05-01T01:30
Asia/Shanghai → 2024-05-01T09:30
America/New_York → 2024-04-30T21:30
ZoneId.of("Asia/Shanghai") 是 ZoneRegion,ZoneOffset.ofHours(8) 是 ZoneOffset;ZoneId.of("+08:00") = +08:00(ZoneOffset)春季跳时:2024-03-10 02:30 在纽约不存在(02:00 直接跳到 03:00),atZone 的结果 = 2024-03-10T03:30-04:00[America/New_York](被推到 03:30) 秋季回拨:2024-11-03 01:30 出现两次,atZone 默认选较早的 = 2024-11-03T01:30-04:00[America/New_York];withLaterOffsetAtOverlap() = 2024-11-03T01:30-05:00[America/New_York];两个瞬间相差 PT1H ZoneRules.getValidOffsets(02:30 春季) = [](空列表 = 不存在),getValidOffsets(01:30 秋季) = [-04:00, -05:00]
起点 2024-03-09T12:00-05:00[America/New_York] plusDays(1)(日历上加一天)= 2024-03-10T12:00-04:00[America/New_York];plus(Duration.ofHours(24))(加 24 小时)= 2024-03-10T13:00-04:00[America/New_York] Duration.between(2024-03-10 00:00, 2024-03-11 00:00 纽约) = PT23H(跳时那天只有 23 小时) Period.between(同样两个日期) = P1D(Period 数日历天数) LocalDateTime 不知道 DST:LocalDateTime(2024-03-09T12:00).plusHours(24) = 2024-03-10T12:00
2024-01-31 plusMonths(1) = 2024-02-29;2023-01-31 plusMonths(1) = 2023-02-28(落到月底,不是下个月 3 号)
2024-01-31 plusMonths(1).plusMonths(1) = 2024-03-29;plusMonths(2) = 2024-03-31(分两步加和一步加不一样)
LocalDate.parse("2024-02-30") → DateTimeParseException: Text '2024-02-30' could not be parsed: Invalid date 'FEBRUARY 30'
LocalDate.of(2024, 2, 30) → DateTimeException: Invalid date 'FEBRUARY 30'
LocalDate.of(2018, 11, 4).atStartOfDay(ZoneId.of("America/Sao_Paulo")) = 2018-11-04T01:00-02:00[America/Sao_Paulo](2018-11-04 在圣保罗午夜跳时,一天的开始是 01:00)
Clock.fixed 注入的时间:LocalDate.now(fixed) = 2024-05-01(测试时可控)
DateTimeFormatter.ISO_INSTANT 格式化 Instant:1970-01-01T00:00:00Z;用 ofPattern("yyyy-MM-dd HH:mm") 格式化 Instant 会失败:UnsupportedTemporalTypeException: Unsupported field: YearOfEra