Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Determine daylight saving time for US ZoneIds in Java

I need to find out whether an Instant is in DST or not. I would expect it to work like that:

ZoneId z = ZoneId.of("America/New_York");
ZoneRules zr = z.getRules();
TimeZone tz = TimeZone.getTimeZone(z);

Instant summer = ZonedDateTime.of(2018, 5, 1, 2, 2, 2, 2, z).toInstant();
Instant winter = ZonedDateTime.of(2018, 11, 1, 2, 2, 2, 2, z).toInstant();

System.out.println("ZoneRules winter: " + zr.isDaylightSavings(winter));
System.out.println("ZoneRules summer: " + zr.isDaylightSavings(summer));
System.out.println("TimeZone winter: " + tz.inDaylightTime(Date.from(winter)));
System.out.println("TimeZone summer: " + tz.inDaylightTime(Date.from(summer)));

but my output for "America/New_York" and other US timezones is always:

ZoneRules winter: true
ZoneRules summer: true
TimeZone winter: true
TimeZone summer: true

ZoneRules.getOffset() also always returns the same value.

However, I don't see the same behaviour when working with European timezones. With ZoneId.of("Europe/London") or ZoneId.of("Europe/Amsterdam") I am getting the expected result:

ZoneRules winter: false
ZoneRules summer: true
TimeZone winter: false
TimeZone summer: true

What am I missing?

Here is some example code on ideone.

like image 910
Tim Jansen Avatar asked Feb 15 '26 21:02

Tim Jansen


1 Answers

Your winter variable is equivalent to November 1st 2018 in New York. But in 2018, in New York timezone, DST ends in November 4th, so the winter variable is still in DST.

You can check when the next transition will be using the nextTransition method:

System.out.println(zr.nextTransition(winter));

This will print:

Transition[Overlap at 2018-11-04T02:00-04:00 to -05:00]

Meaning that in November 4th, at 2 AM, clocks will be set 1 hour back (the "fall back" part of "spring forward/fall back rule"), and the offset will be changed from -04:00 to -05:00.

You can check that by creating the equivalent Instant:

// November 4th, at 02:02 AM (after DST transition)
Instant winter = ZonedDateTime.of(2018, 11, 4, 2, 2, 2, 2, z).toInstant();
System.out.println(zr.isDaylightSavings(winter)); // false

Another way to check the transition dates is to loop through the transtions provided by the ZoneRules:

zr.getTransitions().forEach(System.out::println);

Some zones don't have specific transitions for each year (that's the case of America/New_York), but instead they have transition rules (such as "DST starts at the third Sunday of October"), so if you don't find a transition for a specific year using the getTransitions() method, you can check the transition rules:

zr.getTransitionRules().forEach(r -> System.out.println(r.createTransition(2018)));

For America/New_York, the output is:

Transition[Gap at 2018-03-11T02:00-05:00 to -04:00]
Transition[Overlap at 2018-11-04T02:00-04:00 to -05:00]

like image 144
diston Avatar answered Feb 17 '26 11:02

diston



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!