Kees Jan Koster
Kees Jan Koster

Reputation: 93

Java SimpleDateFormat parse result off by one hour (and yes, I set the time zone)

Riddle me this: why does this simple JUnit assertion fail?

public void testParseDate() throws ParseException {
    final SimpleDateFormat formatter = new SimpleDateFormat(
            "yyyy-MM-dd HH:mm:ss z");
    formatter.setTimeZone(UTC);
    final Calendar c = new GregorianCalendar();
    c.setTime(formatter.parse("2013-03-02 11:59:59 UTC"));

    assertEquals(11, c.get(HOUR_OF_DAY));
}

I would have expected the hour of day to be 11, but according to JUnit, the hour of day is 12.

junit.framework.AssertionFailedError: expected:<11> but was:<12>
at junit.framework.Assert.fail(Assert.java:47)
    ... snip ...

Upvotes: 9

Views: 8287

Answers (2)

Rolf
Rolf

Reputation: 7288

The default constructor of the Gregorian Calendar uses the local timezone of the machine. If that's different from UTC, you get this behavior. Try to use the GregorianCalendar(TimeZone) constructor and pass UTC into that.

This will work:

public void testParseDate() throws Exception {

    TimeZone UTC = TimeZone.getTimeZone("UTC");

    // Create a UTC formatter
    final SimpleDateFormat formatter = new SimpleDateFormat(
            "yyyy-MM-dd HH:mm:ss z");
    formatter.setTimeZone(UTC);

    // Create a UTC Gregorian Calendar (stores internally in UTC, so
    // get(Calendar.HOUR_OF_DAY) returns in UTC instead of in the
    // local machine's timezone.
    final Calendar c = new GregorianCalendar(UTC);

    // Ask the formatter for a date representation and pass that
    // into the GregorianCalendar (which will convert it into
    // it's internal timezone, which is also UTC.
    c.setTime(formatter.parse("2013-03-02 11:59:59 UTC"));

    // Output the UTC hour of day
    assertEquals(11, c.get(Calendar.HOUR_OF_DAY));
}

Upvotes: 8

likeitlikeit
likeitlikeit

Reputation: 5638

You also need to set up the timezone/daylight savings time for the calendar. Have a look at this snippet taken from the documentation:

 // create a Pacific Standard Time time zone
 SimpleTimeZone pdt = new SimpleTimeZone(-8 * 60 * 60 * 1000, ids[0]);

 // set up rules for daylight savings time
 pdt.setStartRule(Calendar.APRIL, 1, Calendar.SUNDAY, 2 * 60 * 60 * 1000);
 pdt.setEndRule(Calendar.OCTOBER, -1, Calendar.SUNDAY, 2 * 60 * 60 * 1000);

 // create a GregorianCalendar with the Pacific Daylight time zone
 // and the current date and time
 Calendar calendar = new GregorianCalendar(pdt);

Upvotes: 1

Related Questions