Consider the following code:
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)));
Printed:
java-8 LocalDateTime hour: 3
java-8 ZonedDateTime hour: 3
Calendar hour: 2
It seems that around this hour Calendar jumps from hour 2 to hour 4 (not necessarily a problem in general if it corresponds to DST change).
I am using AdoptOpenJDK 1.8.0_242, but I've also checked on HotSpot 1.8.0_181 - the same issue.
Why does Calendar report a different hour from ZonedDateTime?
Is this mismatch a known issue?
Whom should I trust more - ZonedDateTime or Calendar in this case?
Assuming that the rules (transition into DST happens on the first Sunday on or after 8 March at 02:00) don't change in 2050, that instant is one where a gap transition occurs (13 March), where the clocks jump from 01:59 to 03:00, so 02:00 doesn't actually exist. Calendar
is quite wrong here.
You can further see how wrong Calendar
is by checking what each of the timezone classes say about the instant in question. ZonedDateTime
uses ZoneId
, whereas Calendar
uses TimeZone
. I compared the outputs of various methods on ZoneId
with that of the TimeZone
counterparts, using this code:
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);
The results are as follows:
-25200
-28800
true
true
-28800
-28800
3600
0
As you can see, both of them think that DST is observed, but TimeZone
thinks DST adds 0 seconds to the standard offset, which makes it think that the actual offset is still -8 hours.
But who knows what happens in 30 years? Let's hope everyone gets rid of DST :)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With