Search code examples
javadatedate-formatdate-formatting

Identifying Repeated Date/Times due to Daylight Savings


I'm trying to parse a date from a String.

I'd like to identify the case where due to daylight savings, the clocks go back and a time is effectively "repeated" in the same day.

For example, based on UK daylight savings time, the clocks go back an hour at 2AM, 27/10/2019.

Therefore:

  • 12:30AM 27/10/2019,
  • One hour later - 1:30AM 27/10/2019,
  • One hour later - 1:30AM 27/10/2019 (as at 2AM, we went back an hour),
  • One hour later - 2:30AM 27/10/2019.

Therefore "1:30AM 27/10/2019" is referring to two different times. This is the case I am trying to identify.

I have created the following, but it uses Date & Calendar classes, and some deprecated methods. I'd like to do this using the new java.time functionality - and I'm hoping there's an easier solution.

public static boolean isDateRepeatedDST(final Date date, TimeZone timeZone) {
    if (timeZone == null) {
        // If not specified, use system default
        timeZone = TimeZone.getDefault();
    }

    if (timeZone.useDaylightTime()) {
        // Initially, add the DST offset to supplied date
        // Handling the case where this is the first occurrence
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.add(Calendar.MILLISECOND, timeZone.getDSTSavings());

        // And determine if they are now logically equivalent
        if (date.toLocaleString().equals(calendar.getTime().toLocaleString())) {
            return true;
        } else {
            // Then try subtracting the DST offset
            // Handling the second occurrence
            calendar = Calendar.getInstance();
            calendar.setTime(date);
            calendar.add(Calendar.MILLISECOND, -timeZone.getDSTSavings());

            if (date.toLocaleString().equals(calendar.getTime().toLocaleString())) {
                    return true;
            }
        }
    }

    // Otherwise
    return false;
}

Solution

  •     ZoneId zone = ZoneId.of("Europe/London");
        ZonedDateTime dateTime = ZonedDateTime.of(2019, 10, 27, 0, 30, 0, 0, zone);
        for (int i = 0; i < 4; i++) {
            System.out.println(dateTime);
            dateTime = dateTime.plusHours(1);
        }
    

    Output:

    2019-10-27T00:30+01:00[Europe/London]
    2019-10-27T01:30+01:00[Europe/London]
    2019-10-27T01:30Z[Europe/London]
    2019-10-27T02:30Z[Europe/London]
    

    You can see that the time 01:30 is repeated and that the offset is different the two times it comes.

    If you want a test for whether a time is repeated:

    public static boolean isDateRepeatedDST(ZonedDateTime dateTime) {
        return ! dateTime.withEarlierOffsetAtOverlap().equals(dateTime.withLaterOffsetAtOverlap());
    }
    

    We can use it in the loop above if we modify the print statement:

            System.out.format("%-37s %s%n", dateTime, isDateRepeatedDST(dateTime));
    
    2019-10-27T00:30+01:00[Europe/London] false
    2019-10-27T01:30+01:00[Europe/London] true
    2019-10-27T01:30Z[Europe/London]      true
    2019-10-27T02:30Z[Europe/London]      false