Determines whether the specified instant is in daylight savings.

Example 17.9 Adjusting for DST Crossovers

Click here to view code image

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.time.ZonedDateTime;
public class DSTAdjustment {
  public static void main(String[] args) {
    adjustForGap();
    adjustForOverlap();
  }
  /**
   * Adjustment due to the time gap at DST crossover.                       (1a)
   * DST starts in US/Central TZ: 2021-03-14T02:00:00,
   * clocks are moved forward 1 hour, resulting in a time gap of 1 hour.
   */
  static void adjustForGap() {
    // Start date and time for DST in US/Central in 2021.                   (2a)
    ZoneId cTZ = ZoneId.of(“US/Central”);
    LocalDate dateStartDST = LocalDate.of(2021, 3, 14);
    LocalTime timeStartDST = LocalTime.of(2, 0);
    LocalDateTime ldtStartDST = LocalDateTime.of(dateStartDST, timeStartDST);
    ZonedDateTime zdtStartDST = ZonedDateTime.of(ldtStartDST, cTZ);
    // Time before the gap.                                                 (3a)
    LocalTime timeBeforeGap = LocalTime.of(1, 30);
    LocalDateTime ldtBeforeGap = LocalDateTime.of(dateStartDST, timeBeforeGap);
    ZonedDateTime zdtBeforeGap = ZonedDateTime.of(ldtBeforeGap, cTZ);
    // Add 1 hour.                                                          (4a)
    ZonedDateTime zdtAfterGap = zdtBeforeGap.plusHours(1);
    // Print a report.                                                      (5a)
    System.out.printf(“Daylight Savings in %s starts at %s “
        + “(spring forward 1 hour).%n”, cTZ, ldtStartDST);
    System.out.println(”                    ___________ZonedDateTime__________”);
    System.out.printf(“%27s %7s %7s %5s %9s %5s%n”,
                      “Date”, “Time”, “Offset”, “TZ”, “DST”, “UTC”);
    printInfo(“(1) Before gap:     “, zdtBeforeGap);
    System.out.println(”    + 1 hour”);
    printInfo(“(2) After gap:      “, zdtAfterGap);
    System.out.println();
    // Add 3 hours:                                                         (6a)
    ZonedDateTime zdtPlus3Hrs = zdtBeforeGap.plusHours(3);
    System.out.printf(“%s + 3 hours = %s%n”, zdtBeforeGap, zdtPlus3Hrs);
    System.out.println();
  }
  /**
   * Adjustment due to the time overlap at DST crossover.                    (1b)
   * DST ends in US/Central TZ: 2021-11-07T02:00:00,
   * clocks are moved backward 1 hour, resulting in a time overlap of 1 hour.
   */
  static void adjustForOverlap() {
    // End date and time for DST in US/Central in 2021.                     (2b)
    ZoneId cTZ = ZoneId.of(“US/Central”);
    LocalDate dateEndDST = LocalDate.of(2021, 11, 7);
    LocalTime timeEndDST = LocalTime.of(2, 0);
    LocalDateTime ldtEndDST = LocalDateTime.of(dateEndDST, timeEndDST);
    ZonedDateTime zdtEndDST = ZonedDateTime.of(ldtEndDST, cTZ);
    // Time before the overlap:                                             (3b)
    LocalTime timeBeforeOverlap = LocalTime.of(0, 30);
    LocalDateTime ldtBeforeOverlap = LocalDateTime.of(dateEndDST,
                                                      timeBeforeOverlap);
    ZonedDateTime zdtBeforeOverlap = ZonedDateTime.of(ldtBeforeOverlap, cTZ);
    // Add 1 hour:                                                          (4b)
    ZonedDateTime zdtInOverlap1 = zdtBeforeOverlap.plusHours(1);
    ZonedDateTime zdtInOverlap2 = zdtInOverlap1.plusHours(1);
    ZonedDateTime zdtAfterOverlap = zdtInOverlap2.plusHours(1);
    // Print a report.                                                      (5b)
    System.out.printf(“Daylight Savings in %s ends at %s (fall back 1 hour).%n”,
                      cTZ, ldtEndDST);
    System.out.println(”                    ___________ZonedDateTime__________”);
    System.out.printf(“%27s %7s %7s %5s %9s %5s%n”,
                      “Date”, “Time”, “Offset”, “TZ”, “DST”, “UTC”);
    printInfo(“(1) Before overlap: “, zdtBeforeOverlap);
    System.out.println(”    + 1 hour”);
    printInfo(“(2) In overlap:     “, zdtInOverlap1);
    System.out.println(”    + 1 hour”);
    printInfo(“(3) In overlap:     “, zdtInOverlap2);
    System.out.println(”    + 1 hour”);
    printInfo(“(4) After overlap:  “, zdtAfterOverlap);
    System.out.println();
    // Add 3 hours:                                                         (6b)
    ZonedDateTime zdtPlus3Hrs = zdtBeforeOverlap.plusHours(3);
    System.out.printf(“%s + 3 hours = %s%n”, zdtBeforeOverlap, zdtPlus3Hrs);
    System.out.println();
  }
  /**
   * Print info for a date-time.                                            (7)
   * @param leadTxt Text to lead the information.
   * @param zdt     Zoned date-time whose info is printed.
   */
  static void printInfo(String leadTxt, ZonedDateTime zdt) {
    System.out.printf(leadTxt + “%10s %5s %6s %5s %-5s %5s%n”,
                      zdt.toLocalDate(), zdt.toLocalTime(),
                      zdt.getOffset(), zdt.getZone(),
                      isDST(zdt), localTimeAtUTC(zdt));
  }
  /**
   * Determine if DST is in effect for a zoned date-time.                   (8)
   * @param zdt  Zoned date-time whose DST status should be determined.
   * @return     true, if DST is in effect.
   */
  static boolean isDST(ZonedDateTime zdt) {
    return zdt.getZone().getRules().isDaylightSavings(zdt.toInstant());
  }
  /**
   *  Find local time at UTC/Greenwich equivalent to local time in          (9)
   *  the specified zoned date-time.
   * @param zdt   Zoned date-time to convert to UTC/Greenwich.
   * @return      Equivalent local time at UTC/Greenwich.
   */
  static LocalTime localTimeAtUTC(ZonedDateTime zdt) {
    return zdt.withZoneSameInstant(ZoneOffset.UTC).toLocalTime();
  }
}

Analogous to the plus() methods, the of() methods also make adjustments at DST crossings. Sticking to the DST information from Example 17.9, if we try to create a zoned date-time with a time that is in the gap, the of() method typically moves the time by the length of the gap (1 hour) into DST.

Click here to view code image

ZonedDateTime zdt1 = ZonedDateTime.of(
    LocalDate.of(2021, 3, 14),
    LocalTime.of(2, 30),                // Time 02:30 is in the gap.
    ZoneId.of(“US/Central”));
System.out.println(zdt1);               // 2021-03-14T03:30-05:00[US/Central]

For a time in the overlap, the offset is ambiguous—it can be -05:00 for DST or -06:00 for standard time. Typically, the of() methods return a zoned date-time with the DST offset, as shown in the following code:

Click here to view code image

ZonedDateTime zdt2 = ZonedDateTime.of(
    LocalDate.of(2021, 11, 7),
    LocalTime.of(1, 30),                // Time 01:30 in the overlap.
    ZoneId.of(“US/Central”));
System.out.println(zdt2);               // 2021-11-07T01:30-05:00[US/Central]

The withField() methods behave analogously to the to() methods when it comes to DST crossings. If we try to create a zoned date-time with the time 02:00 that is in the gap, the withHour() method typically moves the time by the length of the gap (1 hour) into DST.

Click here to view code image

ZonedDateTime zdt3 = ZonedDateTime.of(
    LocalDate.of(2021, 3, 14), LocalTime.of(0, 0), ZoneId.of(“US/Central”)
  ).withHour(2);                     // Time 02:00 is in the gap.
System.out.println(zdt3);            // 2021-03-14T03:00-05:00[US/Central]

For a time in the overlap, the withMinute() method returns a zoned date-time with the DST offset, as shown in the following code:

Click here to view code image

ZonedDateTime zdt4 = ZonedDateTime.of(
    LocalDate.of(2021, 11, 7), LocalTime.of(1, 0), ZoneId.of(“US/Central”)
  ).withMinute(30);                 // Time 01:30 is in the overlap.
System.out.println(zdt4);           // 2021-11-07T01:30-05:00[US/Central]

Finally, the result of temporal arithmetic with zoned date-times can depend on whether date units or time units are involved. We illustrate the behavior using the following zoned date-time that is before the crossover from DST to standard time.

Click here to view code image

ZonedDateTime zdtBeforeOverlap = ZonedDateTime.of(
    LocalDate.of(2021, 11, 7),
    LocalTime.of(0, 30),             // Time 00:30 is before the DST crossover.
    ZoneId.of(“US/Central”));

We add 1 day with the plusDays() method and 24 hours with the plusHours() method to the zoned date-time using the code below. Number of days is measured by the date unit days, and number of hours by the time unit hours. From the output we see that the results are different. The day was added to the date-time and converted back to a zoned date-time with the offset adjusted, without affecting the time part; that is, date units operate on the local timeline. Adding 24 hours results in a zoned-based time that is exactly a duration of 24 hours later, taking the DST crossover into consideration; that is, time units operate on the instant timeline.

Click here to view code image

// Date units and time units.
System.out.printf(“%s + 1 day    = %s%n”,
    zdtBeforeOverlap, zdtBeforeOverlap.plusDays(1));        // (1) Add 1 day.
System.out.printf(“%s + 24 hours = %s%n”,
    zdtBeforeOverlap, zdtBeforeOverlap.plusHours(24));      // (2) Add 24 hours.

Output from the print statements:

Click here to view code image

2021-11-07T00:30-05:00[US/Central] + 1 day    = 2019-11-04T00:30-06:00[US/Central]
2021-11-07T00:30-05:00[US/Central] + 24 hours = 2021-11-07T23:30-06:00[US/Central]

By the same token, adding a Period (that has only date fields) and a Duration (that has only time fields) using the plus(Period.ofDays(1)) and the plus(Duration .ofHours(24)) method calls instead at (1) and (2) above, respectively, will give the same results.

Leave a Reply

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