为什么 ZonedDateTime 和 Calendar 在 2050 年的时间上不一致?
Why do ZonedDateTime and Calendar disagree on the hour in year 2050?
考虑以下代码:
ZoneId zoneId = ZoneId.of("America/Los_Angeles");
long currMillis = 2530778400000L;
Instant curr = Instant.ofEpochMilli(currMillis);
LocalDateTime dt = LocalDateTime.ofInstant(curr, zoneId); //the local one just for completeness
ZonedDateTime zdt = ZonedDateTime.ofInstant(curr, zoneId);
Calendar calendar = GregorianCalendar.from(zdt);
System.out.println(String.format("%-30s %s", "java-8 LocalDateTime hour:", dt.toLocalTime().getHour()));
System.out.println(String.format("%-30s %s", "java-8 ZonedDateTime hour:", zdt.toLocalTime().getHour()));
System.out.println(String.format("%-30s %s", "Calendar hour:", calendar.get(Calendar.HOUR_OF_DAY)));
打印:
java-8 LocalDateTime hour: 3
java-8 ZonedDateTime hour: 3
Calendar hour: 2
似乎在这一点左右,日历从第 2 点跳到第 4 点(如果它对应于 DST 更改,一般来说不一定是问题)。
我正在使用 AdoptOpenJDK 1.8。0_242,但我也检查了 HotSpot 1.8。0_181 - 同样的问题。
为什么日历报告的时间与 ZonedDateTime 不同?
这种不匹配是已知问题吗?
我应该更信任谁 - 在这种情况下是 ZonedDateTime 还是 Calendar?
假设规则(向 DST 的过渡发生在 3 月 8 日或之后的第一个星期日 02:00)在 2050 年不改变,那一刻是间隙过渡发生的时刻(3 月 13 日) ,其中时钟从 01:59 跳到 03:00,因此 02:00 实际上并不存在。 Calendar
这里是完全错误的。
您可以通过检查每个时区 类 对相关时刻的描述来进一步了解 Calendar
有多么错误。 ZonedDateTime
使用 ZoneId
,而 Calendar
使用 TimeZone
。我使用以下代码将 ZoneId
上各种方法的输出与 TimeZone
对应方法的输出进行了比较:
ZoneId zoneId = ZoneId.of("America/Los_Angeles");
long currMillis = 2530778400000L;
Instant curr = Instant.ofEpochMilli(currMillis);
TimeZone tz = TimeZone.getTimeZone(zoneId);
// what's the actual offset at that instant?
System.out.println(zoneId.getRules().getOffset(curr).getTotalSeconds());
System.out.println(tz.getOffset(currMillis) / 1000);
// is DST observed at that instant?
System.out.println(zoneId.getRules().isDaylightSavings(curr));
System.out.println(tz.inDaylightTime(new Date(currMillis)));
// what's the standard offset at that instant?
System.out.println(zoneId.getRules().getStandardOffset(curr).getTotalSeconds());
System.out.println(tz.getRawOffset() / 1000);
// how many seconds does DST add to the standard offset at that instant?
System.out.println(zoneId.getRules().getDaylightSavings(curr).getSeconds());
Calendar calendar = GregorianCalendar.from(ZonedDateTime.ofInstant(curr, zoneId));
System.out.println(calendar.get(Calendar.DST_OFFSET) / 1000);
结果如下:
-25200
-28800
true
true
-28800
-28800
3600
0
如你所见,他们都认为遵守夏令时,但TimeZone
认为夏令时在标准偏移量上增加了0秒,这使得它认为实际偏移量仍然是-8小时。
但谁知道 30 年后会发生什么?让我们希望每个人都摆脱 DST :)
考虑以下代码:
ZoneId zoneId = ZoneId.of("America/Los_Angeles");
long currMillis = 2530778400000L;
Instant curr = Instant.ofEpochMilli(currMillis);
LocalDateTime dt = LocalDateTime.ofInstant(curr, zoneId); //the local one just for completeness
ZonedDateTime zdt = ZonedDateTime.ofInstant(curr, zoneId);
Calendar calendar = GregorianCalendar.from(zdt);
System.out.println(String.format("%-30s %s", "java-8 LocalDateTime hour:", dt.toLocalTime().getHour()));
System.out.println(String.format("%-30s %s", "java-8 ZonedDateTime hour:", zdt.toLocalTime().getHour()));
System.out.println(String.format("%-30s %s", "Calendar hour:", calendar.get(Calendar.HOUR_OF_DAY)));
打印:
java-8 LocalDateTime hour: 3
java-8 ZonedDateTime hour: 3
Calendar hour: 2
似乎在这一点左右,日历从第 2 点跳到第 4 点(如果它对应于 DST 更改,一般来说不一定是问题)。
我正在使用 AdoptOpenJDK 1.8。0_242,但我也检查了 HotSpot 1.8。0_181 - 同样的问题。
为什么日历报告的时间与 ZonedDateTime 不同?
这种不匹配是已知问题吗?
我应该更信任谁 - 在这种情况下是 ZonedDateTime 还是 Calendar?
假设规则(向 DST 的过渡发生在 3 月 8 日或之后的第一个星期日 02:00)在 2050 年不改变,那一刻是间隙过渡发生的时刻(3 月 13 日) ,其中时钟从 01:59 跳到 03:00,因此 02:00 实际上并不存在。 Calendar
这里是完全错误的。
您可以通过检查每个时区 类 对相关时刻的描述来进一步了解 Calendar
有多么错误。 ZonedDateTime
使用 ZoneId
,而 Calendar
使用 TimeZone
。我使用以下代码将 ZoneId
上各种方法的输出与 TimeZone
对应方法的输出进行了比较:
ZoneId zoneId = ZoneId.of("America/Los_Angeles");
long currMillis = 2530778400000L;
Instant curr = Instant.ofEpochMilli(currMillis);
TimeZone tz = TimeZone.getTimeZone(zoneId);
// what's the actual offset at that instant?
System.out.println(zoneId.getRules().getOffset(curr).getTotalSeconds());
System.out.println(tz.getOffset(currMillis) / 1000);
// is DST observed at that instant?
System.out.println(zoneId.getRules().isDaylightSavings(curr));
System.out.println(tz.inDaylightTime(new Date(currMillis)));
// what's the standard offset at that instant?
System.out.println(zoneId.getRules().getStandardOffset(curr).getTotalSeconds());
System.out.println(tz.getRawOffset() / 1000);
// how many seconds does DST add to the standard offset at that instant?
System.out.println(zoneId.getRules().getDaylightSavings(curr).getSeconds());
Calendar calendar = GregorianCalendar.from(ZonedDateTime.ofInstant(curr, zoneId));
System.out.println(calendar.get(Calendar.DST_OFFSET) / 1000);
结果如下:
-25200
-28800
true
true
-28800
-28800
3600
0
如你所见,他们都认为遵守夏令时,但TimeZone
认为夏令时在标准偏移量上增加了0秒,这使得它认为实际偏移量仍然是-8小时。
但谁知道 30 年后会发生什么?让我们希望每个人都摆脱 DST :)