javaparsingdatedate-formatsimpledateformat

Issue with java DateFormat


Following is a piece of code that I am running.

@Test
public void testMyMehotd() {
    String expected = "2012-09-12T20:13:47.796327Z";
    DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSSSS'Z'");
    //df.setTimeZone(TimeZone.getTimeZone("UTC"));
    Date d = null;
    try {
        d = df.parse(expected);
    } catch (ParseException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
        return;
    }

    String actual = df.format(d);

    System.out.println(expected);
    System.out.println(actual);

}

but the output is different than what I expect.

expected : 2012-09-12T20:13:47.796327Z
actual   : 2012-09-12T20:27:03.000327Z

Can someone tell me the reason for this and what is the solution.

Thanks in advance.


Solution

  • Whenever you exceed 999 milliseconds, DateFormat will try to add the remaining milliseconds to your date. Consider the following simpler example:

     String expected = "2012-09-12T20:13:47.1001Z";
     DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSS'Z'");
     Date d = df.parse(expected);
    

    The resulting date will be 2012-09-12T20:13:48.0001. That is, since you have 1001 milliseconds, you get 1 extra second (1000 milliseconds), and 1 millisecond (1001 % 1000). Thus instead of 47 seconds as in the original date, you get 48 seconds.


    This is also what happens if you try to parse a date with an invalid number of days in a month. For example, if you try to add an extra day to September, and parse 2012-09-31:

    String expected = "2012-09-31";
    DateFormat df = new SimpleDateFormat("yyyy-MM-dd");
    Date d = df.parse(expected);
    System.out.println(df.format(d));
    

    You'll actually get 2012-10-01. Again, that's because DateFormat will detect that the 31st day of September is not valid, and will try to use heuristics to transform the Date, thus adding one day, ending up with the first day of the next month.

    There's an option to tell the parser not to use these heuristics, by setting lenient mode to false with:

    df.setLenient(false);
    

    However, using this mode, both above examples will throw a ParseException.