Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

Tags:

java

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 ...
like image 579
Kees Jan Koster Avatar asked Apr 13 '13 18:04

Kees Jan Koster


2 Answers

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));
}
like image 108
Rolf Avatar answered Oct 23 '22 15:10

Rolf


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);
like image 39
likeitlikeit Avatar answered Oct 23 '22 17:10

likeitlikeit