Eduard Korenschi
Eduard Korenschi

Reputation: 236

SimpleDateFormat behaves inconsistently

See the following piece of code:

String timeString = "1980-01-01T14:00:00+0300";
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ");
Date date2 = sdf.parse(timeString);

// sdf.getCalendar().get(Calendar.ZONE_OFFSET);
System.out.println(sdf.format(date2));

now, I'm in a country that has +2h offset, +1 daylight savings(at the moment). If I run this code as it is, it will print

1980-01-01T13:00:00+0200

If I uncomment the line asking about the calendar's offset, the output of the program is

1980-01-01T14:00:00+0300

Any idea why is that happening, and how can I get a consistent output?

To avoid any more unclear things: Since I'm handling some legacy code, java 8 is not an option. And yes, the key point here is WHY, and not what are the workarounds? And there are 2 WHYs:

  1. Why do i pass a +0300 TZ and by default i receive a +0200 one? (SimpleDateFormat should always use TimeZone.getDefault unless otherwise specified).
  2. Why does it give a different answer just because I call a getter on it's calendar instance.

Upvotes: 7

Views: 150

Answers (3)

hinneLinks
hinneLinks

Reputation: 3736

SimpleDateFormate uses Calendar to create the Date. The Date-Object is created with the Timestamp, wich is Calculated in java.util.GregorianCalendar.computeTime(). There in Line 2789 the initial time zone is used (which got set java.text.SimpleDateFormat.initializeCalendar(Locale)). Thats why you see the wrong Timezone.

When you call get(Calendar.ZONE_OFFSET) the Method java.util.GregorianCalendar.computeFields() is called, which uses the Timezone that was set initially.

I Guess this is a Bug.

Upvotes: 0

Evgeniy Dorofeev
Evgeniy Dorofeev

Reputation: 135992

sdf.parse changes formatter's internal calendar zone offset to +0300

    System.out.println(sdf.getCalendar());
    sdf.parse(timeString);
    System.out.println(sdf.getCalendar());

you can see the difference at the end of output lines

... ,ZONE_OFFSET=7200000,DST_OFFSET=0]
... ,ZONE_OFFSET=10800000,DST_OFFSET=0]

sdf.getCalendar().get(Calendar.ZONE_OFFSET); restores calendar's zone offset back to current timezone

Upvotes: 0

meskobalazs
meskobalazs

Reputation: 16041

The problem is, that Calendar#get is not a simple getter, it looks like this:

public int  get(int field)
{
    complete();
    return internalGet(field);
}

where complete does this, according to the Javadoc:

Fills in any unset fields in the calendar fields. First, the computeTime() method is called if the time value (millisecond offset from the Epoch) has not been calculated from calendar field values. Then, the computeFields() method is called to calculate all calendar field values.

I looked up the source here, but the code is the same for the latest Java version too.

Upvotes: 2

Related Questions