Daylight Savings

If a time zone practices daylight savings, the time zone offset of a ZonedDateTime can be different depending on whether daylight saving time (DST) or standard time (for the rest of the year) is in effect. Zone rules associated with the zone ID of a zoned date-time are used to determine the right zone offset for time zones that practice daylight savings.

A time gap occurs when the clock is moved forward at the start of DST, and a time overlap occurs when the clock is moved backward at the end of DST. Usually the gap and the overlap are 1 hour. In that case, when the time gap occurs, an hour is lost and that day has only 23 hours, whereas when a time overlap occurs, an hour is gained and that day has 25 hours. Care should be exercised when dealing with zoned date-times that can involve crossovers to and from DST. Luckily, the methods of(), with(), plus(), and minus() of the ZonedDateTime class take daylight savings into consideration.

As an example to illustrate daylight savings, we will use the US/Central time zone. For this time zone, DST starts at 02:00:00 on 14 March in 2021, when the clocks are moved forward by 1 hour, resulting in the hour between 02:00:00 and 03:00:00 being lost. The gap in this case is 1 hour. The day on 2021-03-14 will only be 23 hours long.

DST for the US/Central time zone ends at 02:00:00 on 7 November in 2021, when clocks are moved backward by 1 hour, resulting in the hour before 02:00:00 being repeated twice. The overlap in this case is 1 hour. The day on 2021-11-07 will be 25 hours long.

The following output from Example 17.9 illustrates what happens when the plus-Hours() method increments a zoned date-time across the time gap.

Click here to view code image

Daylight Savings in US/Central starts at 2021-03-14T02:00 (spring forward 1 hour).
                    ___________ZonedDateTime__________
                       Date    Time  Offset    TZ       DST   UTC
(1) Before gap:     2021-03-14 01:30 -06:00 US/Central false 07:30
    + 1 hour
(2) After gap:      2021-03-14 03:30 -05:00 US/Central true  08:30

Line (1) above shows the following information about a zoned date-time that is before the gap: Date (2021-03-14), Time (01:30), Offset (-06:00), TZ (US/Central), DST that indicates whether it is in effect (false), and UTC equivalent of the time (07:30). Note that the time 01:30 is before the gap. Adding 1 hour to the zoned date-time in line (1) puts the resulting time (02:30) in the gap, which does not exist. The plusH-ours() method increments the expected time 02:30 by the gap length to 03:30 and increments the offset -6:00 by the gap length to -05:00 to comply with DST. Line (2) shows the final result of the operation. DST is now in effect. The UTC equivalent time is now 08:30, an hour after 07:30, as we would expect.

The following output from Example 17.9 illustrates what happens when the plus-Hours() method increments a zoned date-time successively across the time overlap.

Click here to view code image

Daylight Savings in US/Central ends at 2021-11-07T02:00 (fall back 1 hour).
                    ___________ZonedDateTime__________
                       Date    Time  Offset    TZ       DST   UTC
(1) Before overlap: 2021-11-07 00:30 -05:00 US/Central true  05:30
    + 1 hour
(2) In overlap:     2021-11-07 01:30 -05:00 US/Central true  06:30
    + 1 hour
(3) In overlap:     2021-11-07 01:30 -06:00 US/Central false 07:30
    + 1 hour
(4) After overlap:  2021-11-07 02:30 -06:00 US/Central false 08:30

Line (1) shows a zoned date-time before the overlap with the following information: Date (2021-11-07), Time (00:30), Offset (-05:00), TZ (US/Central), DST that indicates whether it is in effect (true), and UTC equivalent of the time (05:30). Again note that the time 00:30 is before the time overlap. Lines (2), (3), and (4) show the result of successively adding 1 hour to the resulting zoned date-time from the previous operation, starting with the zoned date-time in line (1).

Adding 1 hour to the time 00:30 in line (1) with DST in effect changes the time to 01:30, which is in the overlap, but before the DST crossover at 02:00. The result is shown in line (2).

Adding 1 hour to the time 01:30 in line (2) with DST in effect does not change the time. The operation only decrements the offset -05:00 by the overlap length (1 hour) to -06:00, as the time 01:30 is still in the overlap after the DST crossover because it is repeated, but now the standard time is in effect. The result is shown in line (3).

Adding 1 hour to the time 01:30 in line (3) with standard time in effect changes the time to 02:30. The resulting time 02:30 is not in the overlap. The result is shown in line (4). The result would have been the same if we had added 3 hours to the zoned date-time in line (1): the time would be incremented by 2 hours (3 – overlap length) and the offset decremented by the overlap length (1 hour).

The last column, UTC, also shows that the time at UTC/Greenwich changed successively by 1 hour as a result of the plus operations.

In Example 17.9, the methods adjustForGap() at (1a) and adjustForOverlap() at (1b) create the scenarios for DST crossovers discussed above. The method printInfo() at (7) prints the result of each plus operation. The essential lines of code are (4a) and (4b) that perform the plus operations, with the rest of the code creating zoned date-times (2a, 3a, 2b, 3b) and printing formatted output (5a, 5b).

The method isDST() at (8) determines if DST is in effect for a zoned date-time. The method localTimeAtUTC() at (9) returns the UTC equivalent of the time in a zoned date-time. These auxiliary methods are simple but instructive examples of operations on zoned date-times.

The zone rules associated with a time zone can be obtained by calling the ZoneId.getRules() method on a zone ID. The zone rules are represented by the java.time.zone.ZoneRules class that provides the isDaylightSavings() method to determine whether an instant is in daylight savings. A zoned date-time can be converted to an instant by the toInstant() method.

Click here to view code image

// java.time.zone.ZoneRules
boolean isDaylightSavings(Instant instant)

Leave a Reply

Your email address will not be published. Required fields are marked *