Parsing a date’s ordinal indicator ( st, nd, rd, th ) in a date-time string
Java's SimpleDateFormat doesn't support an ordinal suffix, but the ordinal suffix is just eye candy - it is redundant and can easily be removed to allow a straightforward parse:
Date date = new SimpleDateFormat("MMM dd yyyy hh:mma")
.parse(str.replaceAll("(?<=\\d)(st|nd|rd|th)", ""));
The replace regex is so simple because those sequences won't appear anywhere else in a valid date.
To handle any language that appends any length of ordinal indicator characters from any language as a suffix:
Date date = new SimpleDateFormat("MMM dd yyyy hh:mma")
.parse(str.replaceAll("(?<=\\d)(?=\\D* \\d+ )\\p{L}+", ""));
Some languages, eg Mandarin, prepend their ordinal indicator, but that could be handled too using an alternation - left as an exercise for the reader :)
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 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).
ParseExact not parsing string with day, date with ordinal but no year
If you're receiving a 24h format time, then you should parse the string as "dddd d\"th\" MMMM \"at\" HH:mm"
(notice the uppercase Hs).
python format datetime with st, nd, rd, th (english ordinal suffix) like PHP's S
The django.utils.dateformat has a function format
that takes two arguments, the first one being the date (a datetime.date
[[or datetime.datetime
]] instance, where datetime
is the module in Python's standard library), the second one being the format string, and returns the resulting formatted string. The uppercase-S
format item (if part of the format string, of course) is the one that expands to the proper one of 'st', 'nd', 'rd' or 'th', depending on the day-of-month of the date in question.
Related Topics
The Difference Between the Runnable and Callable Interfaces in Java
How to Run Testng from Command Line
Java:Cannot Format Given Object as a Date
Subclassing a Java Builder Class
Can Constructors Throw Exceptions in Java
Quickest Way to Find Missing Number in an Array of Numbers
How to Define a List Bean in Spring
Does a Tcp Socket Connection Have a "Keep Alive"
Converting Many 'If Else' Statements to a Cleaner Approach
Finding Key Associated with Max Value in a Java Map
How to Create Executable Java Program
Add an Background Image to a Panel
Simple Way to Find If Two Different Lists Contain Exactly the Same Elements