Search code examples
javalocaldate

Parsing Date in UpperCase to LocalDate


I'm trying to parse the String FEBRUARY 2019 into a LocalDate.

This is my approach:

LocalDate month = LocalDate.parse("FEBRUARY 2019", DateTimeFormatter.ofPattern("MMMM yyyy"));

Or alternatively setting the Locale.US:

LocalDate month = LocalDate.parse("FEBRUARY 2019", DateTimeFormatter.ofPattern("MMMM yyyy", Locale.US));

But all I get is the following exception:

Exception in thread "main" java.time.format.DateTimeParseException: Text 'FEBRUARY 2019' could not be parsed at index 0

Solution

  • Firstly, I'd suggest that the input you've got isn't a date - it's a year and month. So parse to a YearMonth, and then create a LocalDate from that however you want. I find it simplest to make text handling code only deal with text handling, and perform any other conversions separately when you're in the date/time domain already.

    To handle the case sensitivity issue, you can create a DateTimeFormatter with case-insensitive parsing. Here's a complete example of that:

    import java.time.*;
    import java.time.format.*;
    import java.util.*;
    
    public class Test {
        public static void main(String[] args) {
            // Note: this would probably be a field somewhere so you don't need
            // to build it every time.
            DateTimeFormatter formatter = new DateTimeFormatterBuilder()
                .parseCaseInsensitive()
                .appendPattern("MMMM yyyy")
                .toFormatter(Locale.US);
    
            YearMonth month = YearMonth.parse("FEBRUARY 2019", formatter);
            System.out.println(month);
        }
    }
    

    As an alternative approach which could be of use if you have a different representation, you could build a map and pass that to DateTimeFormatterBuilder.appendText. (I only found this when somehow bungling the code about.)

    import java.time.*;
    import java.time.format.*;
    import java.time.temporal.*;
    import java.util.*;
    
    public class Test {
        public static void main(String[] args) {
            // TODO: Build this map up programmatically instead?            
            Map<Long, String> monthNames = new HashMap<>();
            monthNames.put(1L, "JANUARY");
            monthNames.put(2L, "FEBRUARY");
            monthNames.put(3L, "MARCH");
            monthNames.put(4L, "APRIL");
            monthNames.put(5L, "MAY");
            monthNames.put(6L, "JUNE");
            monthNames.put(7L, "JULY");
            monthNames.put(8L, "AUGUST");
            monthNames.put(9L, "SEPTEMBER");
            monthNames.put(10L, "OCTOBER");
            monthNames.put(11L, "NOVEMBER");
            monthNames.put(12L, "DECEMBER");
    
            // Note: this would probably be a field somewhere so you don't need
            // to build it every time.
            DateTimeFormatter formatter = new DateTimeFormatterBuilder()
                .appendText(ChronoField.MONTH_OF_YEAR, monthNames)
                .appendLiteral(' ')
                .appendPattern("yyyy")
                .toFormatter(Locale.US);
    
            YearMonth month = YearMonth.parse("FEBRUARY 2019", formatter);
            System.out.println(month);
        }
    }