Java time zone with DST prints incorrect time (in negative epochs)

I'm having a hard time understanding the behavior of the following code:

    TimeZone zone = TimeZone.getTimeZone("Asia/Jerusalem");
    DateFormat format = DateFormat.getDateTimeInstance();
    format.setTimeZone(zone);

    //printing out 4 different epoch dates

    //print out using formatter with TZ
    System.out.println(format.format(new Date(-1712458800000L))); 
    //print using Date's toString method
    System.out.println(new Date(-1712458800000L)); 

    System.out.println(format.format(new Date(-57844760000L)));
    System.out.println(new Date(-57844760000L));

    System.out.println(format.format(new Date(-1888228760000L)));
    System.out.println(new Date(-1888228760000L));

    System.out.println(format.format(new Date(1456920000000L)));
    System.out.println(new Date(1456920000000L));

When running on my local machine (Timezone GMT+2 Jerusalem) with "Automatically adjust clock for DST" checked in windows (that makes me GMT+3) It produces the following output:

Sep 26, 1915 11:20:40 PM
Sun Sep 26 23:20:40 IST 1915

Mar 2, 1968 2:00:40 PM
Sat Mar 02 14:00:40 IST 1968

Mar 2, 1910 2:21:20 PM
Wed Mar 02 14:21:20 IST 1910

Mar 2, 2016 2:00:00 PM
Wed Mar 02 14:00:00 IST 2016

But when I'm unchecking it (that makes me GMT+2) running the same code produces

Sep 26, 1915 11:20:40 PM
Sun Sep 26 23:00:00 GMT+02:00 1915

Mar 2, 1968 2:00:40 PM
Sat Mar 02 14:00:40 GMT+02:00 1968

Mar 2, 1910 2:21:20 PM
Wed Mar 02 14:00:40 GMT+02:00 1910

Mar 2, 2016 2:00:00 PM
Wed Mar 02 14:00:00 GMT+02:00 2016

The first and third example differ in the minutes and seconds when using toString() of Date. As you can see, when I'm explicitly setting the TZ using DateFormat it prints out the same result. What am I missing here?

Thanks!

Jon Skeet
people
quotationmark

Let's just look at your 1915 example. The value -1712458800000 as millis-since-the-unix-epoch is 1915-09-26T21:00:00Z - in other words, exactly 9pm UTC.

Now back in 1915, the UTC offset in Jerusalem was +2:20:40, which is why you see "Sep 26, 1915 11:20:40 PM" in the first line of your output. However, when you turn off DST in Windows, either Windows or Java is treating that as saying "Treat this as a fixed time zone of UTC+2." It's not really "Treat this as Jerusalem without DST changes, but with other changes." So you see a value of UTC+2 in your second line, which is "Sun Sep 26 23:00:00 GMT+02:00 1915".

Basically, the concept of "this time zone without DST" is a very odd one, and has been simplified (again, I'm not sure whether it's by Windows or Java) to just a fixed offset. That's fine when the "standard" offset doesn't change, but it causes issues like this when it does. Most time zones haven't changed their standard offset in reasonably-modern history, but there are quite a few changes back in the early 20th century.

people

See more on this question at Stackoverflow