Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java Calendar: Why are UTC offsets being reversed?

I'm trying to grok time-handling, and I've stumbled upon something in Java that has me somewhat baffled. Take this sample code:

public static void main(String[] args)
{
    //Calendar set to 12:00 AM of the current day (Eastern Daylight Time)
    Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("GMT-4"));
    cal.set(Calendar.HOUR_OF_DAY, 0);
    cal.set(Calendar.MINUTE, 0);
    cal.set(Calendar.SECOND, 0);
    cal.set(Calendar.MILLISECOND, 0);
    /////

    //Calendar set to 12:00 AM of the current day (UTC time)
    Calendar utcCal = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
    utcCal.set(Calendar.HOUR_OF_DAY, 0);
    utcCal.set(Calendar.MINUTE, 0);
    utcCal.set(Calendar.SECOND, 0);
    utcCal.set(Calendar.MILLISECOND, 0);
    /////

    long oneHourMilliseconds = 3600000;
    System.out.println((cal.getTimeInMillis() - utcCal.getTimeInMillis()) / oneHourMilliseconds);
}

I visualize the algorithm for calculating the time represented by cal taking 1 of 2 forms:

  1. Calculate the number of milliseconds from the Epoch, add offset (add -4)
  2. Calculate the number of milliseconds from (Epoch + offset). So # of milliseconds from (Epoch - 4 * oneHourMilliseconds).

Both of these algorithms should yield a result that is 4 hours behind that of utcCal, however running the code returns 4 .

Can someone explain to me why cal, despite being set to a time zone 4 hours behind that of utcCal, ends up having a millisecond value 4 hours after that of utcCal? Shouldn't the code be returning -4?

like image 943
Kevin Avatar asked Apr 18 '12 14:04

Kevin


2 Answers

It's an unfortunate piece of history. A time zone with an ID of "GMT-4" is what you'd expect to be "UTC+4", i.e. it's 4 hours ahead of UTC.

From the etcetera file from tzdb:

# We use POSIX-style signs in the Zone names and the output abbreviations,
# even though this is the opposite of what many people expect.
# POSIX has positive signs west of Greenwich, but many people expect
# positive signs east of Greenwich.  For example, TZ='Etc/GMT+4' uses
# the abbreviation "GMT+4" and corresponds to 4 hours behind UTC
# (i.e. west of Greenwich) even though many people would expect it to
# mean 4 hours ahead of UTC (i.e. east of Greenwich).

And from this similar explanation:

If you can at all manage it, avoid definitions and use of the GMT timezones...

like image 145
Jon Skeet Avatar answered Oct 23 '22 10:10

Jon Skeet


The calendar cal is set to 2012-04-18 00:00:00 of the timezone GMT-4.

That moment corresponds to 2012-04-18 04:00:00 in UTC (in other words, when it's 12 AM in the timezone GMT-4, it's 4 AM in UTC).

The calendar utcCal is set to 2012-04-18 00:00:00 of the timezone UTC.

The difference between 2012-04-18 04:00:00 and 2012-04-18 00:00:00 is 4 hours, so you see 4 being printed.

like image 29
Jesper Avatar answered Oct 23 '22 09:10

Jesper