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.
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);