Question: What's going on here? What went wrong?
Two basic things went wrong:
- You tried to hand parse your date string. The recommended way is to use a library method for parsing dates.
- You used the wrong classes.
Date
and GregorianCalendar
are long outdated and no more recommended, also because they were always poorly designed. Furthermore despite their names they don’t represent dates (a Date
is a point in time, while GregorianCalendar
is a date and a time in a particular time zone).
It’s very easy to get things wrong with those old classes, so no wonder you did too, thousands have done before you (just look at how many Stack Overflow questions tesitify to this). What went on more concretely: you correctly passed the numbers 2004, 2 and 9 to the GregorianCalendar
constructor. That constructor takes the arguments to be year, month and day in that order. It furthermore confusingly assumes a 0-based month, where 0 means January, so 2 means March. Hence you get March 9, 2004 at 00:00:00 in your JVM’s default time zone.
But 4/20/2004, then? When months are 0 through 11, 20 cannot be a month. A GregorianCalendar
with default settings doesn’t care, it just extrapolates and keeps counting months into the following year. So month 11 would have been December 2004, month 12 would be January 2005, etc., so we end up with month 20 being September 2005.
What to do instead?
The modern solution to your problem is:
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("M/d/u");
LocalDate date = LocalDate.parse("9/2/2004", dtf);
System.out.println(date);
Output is:
2004-09-02
M/d/u
is a format pattern string specifying that your format consists of month, day of month and year separated by slashes. Be aware that format pattern strings are case sensitive: you need uppercase M
and lowercase d
and u
. All the possible format letters are in the documentation.
Links