Parsing Dates of the Format "January 10Th, 2010" in Java? (With Ordinal Indicators, St|Nd|Rd|Th)

Formatting string to date in java

You can use a DateTimeFormatterBuilder to create a DateTimeFormatter that can parse days-of-month that have the "st", "nd", "rd" and "th" suffixes, and also lowercase AMPM.

// first create a map containing mapping the days of month to the suffixes
HashMap<Long, String> map = new HashMap<>();
for (long i = 1 ; i <= 31 ; i++) {
if (i == 1 || i == 21 || i == 31) {
map.put(i, i + "st");
} else if (i == 2 || i == 22){
map.put(i, i + "nd");
} else if (i == 3 || i == 23) {
map.put(i, i + "rd");
} else {
map.put(i, i + "th");
}
}

DateTimeFormatter dateFormatter = new DateTimeFormatterBuilder()
.appendPattern("MMMM ")
.appendText(ChronoField.DAY_OF_MONTH, map) // here we use the map
.appendPattern(" yyyy HH:mm")
.appendText(ChronoField.AMPM_OF_DAY, Map.of(0L, "am", 1L, "pm")) // here we handle the lowercase AM PM
.toFormatter(Locale.US);

Usage:

LocalDateTime datetime = LocalDateTime.parse("April 5th 2021 12:30pm", dateFormatter);

How to format a non plain date in Java?

Replace all the expected undesired sufiixes by an empty string, and then parse:

    String s = "10th Dec 2019";

SimpleDateFormat fmt = new SimpleDateFormat("dd MMM yyyy", Locale.ENGLISH);
Date d = fmt.parse(s.replaceFirst("th|nd|st|rd", ""));
System.out.println("d = " + d);

How do you format the day of the month to say 11th, 21st or 23rd (ordinal indicator)?

// https://github.com/google/guava
import static com.google.common.base.Preconditions.*;

String getDayOfMonthSuffix(final int n) {
checkArgument(n >= 1 && n <= 31, "illegal day of month: " + n);
if (n >= 11 && n <= 13) {
return "th";
}
switch (n % 10) {
case 1: return "st";
case 2: return "nd";
case 3: return "rd";
default: return "th";
}
}

The table from @kaliatech is nice, but since the same information is repeated, it opens the chance for a bug. Such a bug actually exists in the table for 7tn, 17tn, and 27tn (this bug might get fixed as time goes on because of the fluid nature of StackOverflow, so check the version history on the answer to see the error).

java.text.ParseException: Unparseable date: Augu 16, 1979

The problem is that replace("st", "") also removes the st ending of August, resulting in the input string seen in the error message.

To handle this, you need to make sure the st suffix is right after a digit, so it's part of the day value. You also need to handle all of 1st, 2nd, 3rd, and 4th.

This means that you should use regular expression, like this:

replaceFirst("(?<=\\d)(?:st|nd|rd|th)", "")

Test

public static void main(String[] args) throws Exception {
test("August 20th, 2012");
test("August 21st, 2012");
test("August 22nd, 2012");
test("August 23rd, 2012");
test("August 24th, 2012");
}
static void test(String input) throws ParseException {
String modified = input.replaceFirst("(?<=\\d)(?:st|nd|rd|th)", "");

DateFormat originalFormat = new SimpleDateFormat("MMMM dd, yyyy", Locale.ENGLISH);
DateFormat targetFormat = new SimpleDateFormat("yyyyMMdd");
Date date = originalFormat.parse(modified);
System.out.println(targetFormat.format(date));
}

Output

20120820
20120821
20120822
20120823
20120824


Related Topics



Leave a reply



Submit