Search code examples
javadatedatetimelocaldatelocaltime

How to specify time after daylight saveing time shift in Java


Using the following code:

class Test {
    public static void main(String [] args) {
        LocalDate date = LocalDate.of(2018, 11, 4);
        LocalTime time = LocalTime.of(1, 59);
        ZonedDateTime dt = ZonedDateTime.of(date, time, ZoneId.of("America/New_York"));
        System.out.println(dt.getHour() + ":" + dt.getMinute() + ":" + dt.getSecond());
        dt = dt.plusMinutes(1);
        System.out.println(dt.getHour() + ":" + dt.getMinute() + ":" + dt.getSecond());
        dt = dt.plusMinutes(59);
        System.out.println(dt.getHour() + ":" + dt.getMinute() + ":" + dt.getSecond());
        dt = dt.plusMinutes(1);
        System.out.println(dt.getHour() + ":" + dt.getMinute() + ":" + dt.getSecond());
    }
}

I get

1:59:0
1:0:0
1:59:0
2:0:0

Is there a way to get to the 1:00:00 from after daylight saving time without going through the 1:00:00 from before daylight saving time?


Solution

  • Use ofStrict to specify which offset you want the resulting zoned date time to be on. America/New_York changes from -04:00 to -05:00 at around the time in question, so you want ZoneOffset.ofHours(-5).

    ZonedDateTime dt = ZonedDateTime.ofStrict(
        LocalDateTime.of(date, time), 
        ZoneOffset.ofHours(-5), 
        ZoneId.of("America/New_York")
    );
    

    In case you cannot hardcode the offset in, you can get the offset after using:

    var dateTime = LocalDateTime.of(date, time)
    var zone = ZoneId.of("America/New_York");
    var offsetAfter = zone.getRules()
        .getTransition(dateTime)
        .getOffsetAfter();
    ZonedDateTime dt = ZonedDateTime.ofStrict(
        dateTime, 
        offsetAfter, 
        zone
    );
    

    Or, as Ole V.V. pointed out, you can also use the much shorter:

    ZonedDateTime dt = ZonedDateTime.of(
        date, time, ZoneId.of("America/New_York")
    ).withLaterOffsetAtOverlap();