Wednesday, May 23, 2012

Why is subtracting these two times (in 1927) giving a strange result?


If I run the following program, which parses two date strings referencing times one second apart and compares them:




public static void main(String[] args) throws ParseException {
SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String str3 = "1927-12-31 23:54:07";
String str4 = "1927-12-31 23:54:08";
Date sDt3 = sf.parse(str3);
Date sDt4 = sf.parse(str4);
long ld3 = sDt3.getTime() /1000;
long ld4 = sDt4.getTime() /1000;
System.out.println(ld3);
System.out.println(ld4);
System.out.println(ld4-ld3);
}



The output is:




-1325491905
-1325491552
353



Why is ld4-ld3 not 1 (as I would expect from the one-second difference in the times), but 353 ?



If I change the dates to times a second later:




String str3 = "1927-12-31 23:54:08";
String str4 = "1927-12-31 23:54:09";



Then ld4-ld3 will be 1





UPDATE



Java version:




java version "1.6.0_22"
Java(TM) SE Runtime Environment (build 1.6.0_22-b04)
Dynamic Code Evolution Client VM (build 0.2-b02-internal, 19.0-b04-internal, mixed mode)



Timezone( TimeZone.getDefault() ):




sun.util.calendar.ZoneInfo[id="Asia/Shanghai",
offset=28800000,dstSavings=0,
useDaylight=false,
transitions=19,
lastRule=null]

Locale(Locale.getDefault()): zh_CN


Source: Tips4all

6 comments:

  1. It's a time zone change on December 31st in Shanghai.

    See this page for details of 1927 in Shanghai. Basically at midnight at the end of 1927, the clocks went back 5 minutes and 52 seconds. So "1927-12-31 23:54:08" actually happened twice, and it looks like Java is parsing it as the later possible instant for that local date/time - hence the difference.

    Just another episode in the often weird and wonderful world of time zones.

    ReplyDelete
  2. You've encountered a local time discontinuity:


    When local standard time was about to reach Sunday, 1. January 1928,
    00:00:00 clocks were turned backward 0:05:52 hours to Saturday, 31.
    December 1927, 23:54:08 local standard time instead


    This is not particularly strange and has happened pretty much everywhere at one time or another as timezones were switched or changed due to political or administrative actions.

    ReplyDelete
  3. Ran your code, output:

    -1325466353
    -1325466352
    1


    And:

    -1325466352
    -1325466351
    1


    on:

    $ java -version
    java version "1.6.0_20"
    OpenJDK Runtime Environment (IcedTea6 1.9.7) (fedora-52.1.9.7.fc14-i386)
    OpenJDK Client VM (build 19.0-b09, mixed mode)

    ReplyDelete
  4. The moral of this strangeness is:


    Use dates and times in UTC wherever possible.
    If you can not display a date or time in UTC, always indicate the time-zone.
    If you can not require an input date/time in UTC, require an explicitly indicated time-zone.

    ReplyDelete
  5. When incrementing time you should convert back to UTC and then add or subtract. Use the local time only for display.

    This way you will be able to walk through any periods where hours or minutes happen twice.

    If you converted to UTC, add each second, and convert to local time for display. You would go through 11:54:08 p.m. LMT - 11:59:59 p.m. LMT and then 11:54:08 p.m. CST - 11:59:59 p.m. CST.

    ReplyDelete
  6. Instead of converting each date in long you use the following code

    long i = (sDt4.getTime() - sDt3.getTime()) / (1000);
    System.out.println(i);


    And see the result is:

    1

    ReplyDelete