Java SimpleDateFormat always returning January for Month

TL;DR

    LocalDate parsedDate = OffsetDateTime
            .parse("20050912190509.0Z", DateTimeFormatter.ofPattern("uuuuMMddHHmmss.SX"))
            .toLocalDate();

This yields a LocalDate of 2005-09-12.

java.time

I am contributing the modern answer. Suhas Phartale’s answer is correct and was a good answer when it was written 7 years ago. Now the notoriously troublesome SimpleDateFormat class is long outdated and we have so much better in java.time, the modern Java date and time API. I warmly recommend you use this instead of the old date-time classes.

Details

It seems from your code that you reformat your string from AD before parsing it. There’s no need for that, the string from AD can be parsed directly. We might have parsed it directly into a LocalDate, but I recommend parsing it into an OffsetDateTime to grab the time and offset from the string; as you can see, this can be directly converted to a LocalDate afterwards. A LocalDate is a date without time of day, so it seems to match your requirements better than the old Date class.

The string is in UTC (denoted by the Z in the end). The above gives you the date from the string, that is the date in UTC. If instead you wanted the date it was in your local time zone when it was September 12 19:05 in UTC:

    LocalDate parsedDate = OffsetDateTime.parse(givenString, adDateTimeFormatter)
            .atZoneSameInstant(ZoneId.of("America/Coral_Harbour"))
            .toLocalDate();

I assumed we have declared the formatter a static field:

private static final DateTimeFormatter adDateTimeFormatter
        = DateTimeFormatter.ofPattern("uuuuMMddHHmmss.SX");

In this case the result is the same, for other time zones it will not be. Please substitute your own desired time zone for America/Coral_Harbour. To use the JVM’s time zone setting, specify ZoneId.systemDefault(). Beware, however, that the setting may be changed by other parts of your program or other programs running in the same JVM, so this is fragile.

And the point from Suhas Phartale’s answer is valid in java.time too: format pattern strings are case sensitive, and I needed to use lowercase dd for day of month.

Tutorial

Learn more about java.time in the Oracle tutorial and/or search for other resources on the net.


Make sure you don't use 'mm' instead of 'MM' or 'MMM'. As small m denotes minutes and caps M denotes month.


Change the pattern string from "yyyy/MM/DD" to "yyyy/MM/dd"

SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd");