This started as a simple error: I had YYYY
instead of yyyy
in my format string for a SimpleDateFormat
object. But I'm totally baffled by the results of my tests with the incorrect format string.
This code:
@Test
public void whatTheHell() {
try {
SimpleDateFormat sdf = new SimpleDateFormat("MM/dd/YYYY");
Date d1 = sdf.parse("01/07/2016");
Date d2 = sdf.parse("02/08/2016");
Date d3 = sdf.parse("11/29/2027");
System.out.println(d1.toString());
System.out.println(d2.toString());
System.out.println(d3.toString());
} catch (ParseException pe) {
fail("ParseException: " + pe.getMessage());
}
}
produces this output:
Sun Dec 27 00:00:00 PST 2015
Sun Dec 27 00:00:00 PST 2015
Sun Dec 27 00:00:00 PST 2026
I've read the documentation on the 'Y' parameter here: https://docs.oracle.com/javase/7/docs/api/java/util/GregorianCalendar.html, but I still can't see the logic that's working here. Particularly the last instance: I can kinda-sorta understand how the dates in January (& maybe February) can be translated into December of the previous year, but moving the date of November 29th backwards by 11 months baffles me. And what's so special about December 27th?
Can anyone explain?
MORE INFORMATION
@Jan suggested that relying on the toString() method could be a problem, so I defined a date format to print YYYY MM dd '-' yyyy MM dd
in the same code as above. Here is the additional output:
2016 12 27 - 2015 12 27
2016 12 27 - 2015 12 27
2027 12 27 - 2026 12 27
It's simple: December 27 2015 is day 1 of week 1 of week-year 2016 (and December 27 2026 is day 1 of week 1 of week-year 2027). This can be verified by adding these lines:
SimpleDateFormat odf = new SimpleDateFormat("YYYY-ww-u");
System.out.println(odf.format(d1));
System.out.println(odf.format(d2));
System.out.println(odf.format(d3));
If a SimpleDateFormat
outputs a date it can use all fields: year, month, day, day of week, week of month, week in year, week-year etc.
On parsing, SimpleDateFormat
expects a matching set of values: either day, month, year or day of week, week in year, week-year. Since you supplied a week-year but did not supply day of week and week in year, those to values have been assumed as 1.
The actual values depend on your locale:
(see https://docs.oracle.com/javase/7/docs/api/java/util/GregorianCalendar.html#week_and_year)
On my system (using de-ch locale, with "EEE MMM dd HH:mm:ss zzz yyyy - YYYY-ww-u" as format) I get
Mo Jan 04 00:00:00 MEZ 2016 - 2016-01-1 Mo Jan 04 00:00:00 MEZ 2016 - 2016-01-1 Mo Jan 04 00:00:00 MEZ 2027 - 2027-01-1