Search code examples
javajava-timedatetimeformatter

DateTimeParseException for LocalDateTime object despite having the format mapped


I have a Java 8 application that has to accept any number of date and time formats from a user. Obviously that yields an exhaustive list, as there are many ways to write a date and time. For locale purposes, though, this is all US-formatted dates (and yes, I checked that the locale was indeed en_US).

However, what should be a simple date/time string has been causing a great deal of strife for me. Here is my code:

String dateString = // user generated thing

// Remove whitespace for simplicity's sake
dateString = dateString.replaceAll("\\s+", "");

// There are A LOT of formats here, but I only pasted a small number of them for
// simplicity's sake, including the format in question
DateTimeFormatterBuilder formatBuilder = new DateTimeFormatterBuilder()
    .append(DateTimeFormatter.ofPattern("[MM/dd/yyyy]" + "[MM/dd/yy]" +
            "[MM/dd/yyyyhh:mma]" + "[MM/dd/yyyyh:mma]" + "[MM-dd-yyyyhh:mma]"));

DateTimeFormatter formatter = formatBuilder
    .parseDefaulting(ChronoField.HOUR_OF_DAY, 0)
    .parseDefaulting(ChronoField.MINUTE_OF_HOUR, 0)
    .parseDefaulting(ChronoField.SECOND_OF_MINUTE, 0)
    .parseCaseInsensitive()
    .toFormatter();

LocalDateTime ldt = LocalDateTime.parse(dateString, formatter);

When entering the string "01/05/2024 03:41 pm" (which, with removing the whitespaces, converted to "01/05/202403:41pm") I ended up getting the error:

java.time.format.DateTimeParseException: Text '01/05/202403:41pm' could not be parsed, unparsed text found at index 8

I initially did not remove the whitespace, and had the formats accommodate the whitespace (i.e. I had "MM/dd/yyyy hh:mm a"). This gave me the error:

java.time.format.DateTimeParseException: Text '01/05/2024 03:41 pm' could not be parsed, unparsed text found at index 10

As you can see, I turned on case insensitive parsing, so the lowercase am/pm shouldn't be an issue. Besides, it fails upon index 8 (the second "2" in 2024) without spaces, and on index 10 (the first space) with spaces.

I thought perhaps with the number of formats I have (again, not all of them are shown here), perhaps there was too much ambiguity, so I tested it by only having the MM/dd/yyyy and "MM/dd/yyyy hh:mm a" formats. (I needed the first MM/dd/yyyy for other dates). Unfortunately, this did not work either, so I have no idea what to do.


Solution

  • You don't need to remove the space that separates the date from the time, otherwise you won't be able to distinguish MM/dd/yyyy from MM/dd/yyhh. You also cannot use ChronoField.HOUR_OF_DAY, as it is intended for 24-hour format.

    I suggest you test this code:

    DateTimeFormatter formatter = new DateTimeFormatterBuilder()
            .parseCaseInsensitive()
            .appendPattern("[MM/dd/yyyy][MM/dd/yy][MM-dd-yyyy]")
            .optionalStart()
            .appendPattern(" [h:mm a]")
            .optionalEnd()
            .parseDefaulting(ChronoField.CLOCK_HOUR_OF_AMPM, 12)
            .parseDefaulting(ChronoField.AMPM_OF_DAY, 0)
            .parseDefaulting(ChronoField.MINUTE_OF_HOUR, 0)
            .toFormatter(Locale.US);