You can iterate over known formats and skip ones that throw a DateTimeParseException
.
Note: If you are parsing just a date string into a LocalDateTime
, you will need to build the formatter and specify that the time portion is optional.
import java.time.LocalDateTime;
import java.time.format.*;
import java.time.temporal.ChronoField;
import java.util.*;
public class DateParser {
public static void main(String[] args) {
System.out.println(normalizeDate("2023-05-09T05:55:07Z")); // 2023-05-09
System.out.println(normalizeDate("2023-04-30")); // 2023-04-30
System.out.println(normalizeDate("08-05-2023")); // 2023-08-05
System.out.println(normalizeDate("2023-05-09 00:00:00")); // 2023-05-09
System.out.println(normalizeDate("31-Dec-2021")); // 2021-12-31
System.out.println(normalizeDate("")); // null
}
public static String normalizeDate(String rawDateTimeString) {
return Optional.ofNullable(parseDateString(rawDateTimeString))
.map(displayFormat::format)
.orElse(null);
}
private static LocalDateTime parseDateString(String dateString) {
for (DateTimeFormatter formatter : knownFormats) {
try {
return LocalDateTime.parse(dateString, formatter);
} catch (DateTimeParseException e) {
continue;
}
}
return null;
}
private static final List<DateTimeFormatter> knownFormats = Arrays.asList(
DateTimeFormatter.ISO_DATE_TIME,
dateOnlyFormatter("yyyy-MM-dd"),
dateOnlyFormatter("MM-dd-yyyy"),
DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"),
dateOnlyFormatter("dd-MMM-yyyy").withLocale(Locale.ENGLISH));
private static DateTimeFormatter dateOnlyFormatter(String datePattern) {
// Credit: https://stackoverflow.com/a/40175568/1762224
return new DateTimeFormatterBuilder()
.appendPattern(datePattern)
.optionalStart()
.appendPattern(" HH:mm")
.optionalEnd()
.parseDefaulting(ChronoField.HOUR_OF_DAY, 0)
.parseDefaulting(ChronoField.MINUTE_OF_HOUR, 0)
.toFormatter();
}
private static final DateTimeFormatter displayFormat = DateTimeFormatter.ISO_DATE;
}
Here is a modified version that is simpler as Devin suggested. It ignores the concept of time entirely, and only focuses on date when parsing. It removes the need for the dateOnlyFormatter
method (as seen above).
import java.time.LocalDate;
import java.time.format.*;
import java.util.*;
public class DateParser {
public static void main(String[] args) {
System.out.println(normalizeDate("2023-05-09T05:55:07Z")); // 2023-05-09
System.out.println(normalizeDate("2023-04-30")); // 2023-04-30
System.out.println(normalizeDate("08-05-2023")); // 2023-08-05
System.out.println(normalizeDate("2023-05-09 00:00:00")); // 2023-05-09
System.out.println(normalizeDate("31-Dec-2021")); // 2021-12-31
System.out.println(normalizeDate("")); // null
}
public static String normalizeDate(String rawDateTimeString) {
return Optional.ofNullable(parseDateString(rawDateTimeString))
.map(displayFormat::format)
.orElse(null);
}
private static LocalDate parseDateString(String dateString) {
for (DateTimeFormatter formatter : knownFormats) {
try {
return LocalDate.parse(dateString, formatter);
} catch (DateTimeParseException e) {
continue;
}
}
return null;
}
private static final List<DateTimeFormatter> knownFormats = Arrays.asList(
DateTimeFormatter.ISO_DATE_TIME,
DateTimeFormatter.ofPattern("yyyy-MM-dd"),
DateTimeFormatter.ofPattern("MM-dd-yyyy"),
DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"),
DateTimeFormatter.ofPattern("dd-MMM-yyyy").withLocale(Locale.ENGLISH));
private static final DateTimeFormatter displayFormat = DateTimeFormatter.ISO_DATE;
}