Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-8214243

Different/wrong historical timezone offsets applied in old vs. new time API

XMLWordPrintable

    • x86_64
    • windows_7

      ADDITIONAL SYSTEM INFORMATION :
      Windows 7 Enterprise SP1 64-bit
      java version "1.8.0_191"
      Java(TM) SE Runtime Environment (build 1.8.0_191-b12)
      Java HotSpot(TM) 64-Bit Server VM (build 25.191-b12, mixed mode)

      A DESCRIPTION OF THE PROBLEM :
      When creating a new Date at the start of day in the time zone Europe/Berlin (and possibly other time zones), with a date on or before March 31, 1893, the timezone offset applied differs by 00:06:32 when using java.util.Date/java.util.Calendar vs. java.time.* for the exact same values.
      The offset for Europe/Berlin is currently +1:00:00, however before April 1893 this offset was +0:53:28. When creating a date using java.util.Date() or java.util.Calendar, an offset of +1:00:00 is used. However, the java.time methods (e.g. .atStartOfDay(ZoneId.systemDefault())) apply the +0:53:28 offset, leading to inconsistencies when interoperating with methods that use the old APIs (or vice versa).
      Java should use the same time zone conversion rules regardless of the APIs used.

      STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
      Create a new Date() for the start of day for a day on or before March 31, 1893 when the system default time zone is set to "Europe/Berlin". Create a second date using the java.time methods from a LocalDate for the same date.
      The dates will be different and offset from each other by 00:06:32.

      EXPECTED VERSUS ACTUAL BEHAVIOR :
      EXPECTED -
      The dates are the same, and both are printed as midnight in the system default timezone.
      ACTUAL -
      The dates are different, and one of the output strings does not print as midnight in the system default timezone:

      Sun Feb 05 00:00:00 CET 1893
      -2426806800000
      Sun Feb 05 00:06:32 CET 1893
      -2426806408000
      -> old and new api return different dates
      -> new api date toString() is not start of day

      ---------- BEGIN SOURCE ----------
      import java.time.LocalDate;
      import java.time.ZoneId;
      import java.util.Date;
      import java.util.TimeZone;

      public class Main {
        public static void main(String[] args) {
          TimeZone defaultTimeZone = TimeZone.getDefault();
          try {
            TimeZone.setDefault(TimeZone.getTimeZone(ZoneId.of("Europe/Berlin")));

            // note: date must be <= 1893-04-01
            LocalDate ld = LocalDate.of(1893, 2, 5);

            // old API: timezone offset of +1:00:00 is applied
            Date oldApiDate = new Date(ld.getYear() - 1900, ld.getMonthValue() - 1, ld.getDayOfMonth(), 0, 0, 0);
            System.out.println(oldApiDate.toString());
            System.out.println(oldApiDate.getTime());
            // Sun Feb 05 00:00:00 CET 1893
            // -2426806800000

            // new API: historical timezone offset of +0:53:28 before April 1893 is applied
            Date newApiDate = Date.from(ld.atStartOfDay(ZoneId.systemDefault()).toInstant());
            System.out.println(newApiDate.toString());
            System.out.println(newApiDate.getTime());
            // Sun Feb 05 00:06:32 CET 1893
            // -2426806408000

            if (oldApiDate.getTime() != newApiDate.getTime()) {
              System.err.println("-> old and new api return different dates");
            }
            if (!oldApiDate.toString().contains("00:00:00")) {
              System.err.println("-> old api date toString() is not start of day");
            }
            if (!newApiDate.toString().contains("00:00:00")) {
              System.err.println("-> new api date toString() is not start of day");
            }
          }
          finally {
            TimeZone.setDefault(defaultTimeZone);
          }
        }
      }
      ---------- END SOURCE ----------

      CUSTOMER SUBMITTED WORKAROUND :
      Do not use the java.time methods for start-of-day calculations or timezone conversions if interoperability with methods using java.util.Date/Calendar is necessary.

      FREQUENCY : always


            naoto Naoto Sato
            webbuggrp Webbug Group
            Votes:
            0 Vote for this issue
            Watchers:
            3 Start watching this issue

              Created:
              Updated:
              Resolved: