Explain Codes LogoExplain Codes Logo

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

java
date-formatting
java-time
unit-testing
Alex KataevbyAlex Kataev·Nov 19, 2024
TLDR

The quickest way to append ordinal indicators (st, nd, rd, th) to day numbers in the context of Java can be done as follow:

public static String formatDay(int day) { Preconditions.checkArgument(day > 0 && day <= 31, "Invalid day: %s", day); switch (day) { case 11: case 12: case 13: return day + "th"; // because 11th, 12th, and 13th are special, they get the "th". default: return day + (day % 10 == 1 ? "st" : // if last digit is 1, use "st". (day % 10 == 2 ? "nd" : // if last digit is 2, use "nd". (day % 10 == 3 ? "rd" : "th"))); // if last digit is 3, use "rd". Otherwise, use "th". } } // Add some spice to your life, or at least to your date formatting... String formattedDate = new SimpleDateFormat("MMMM yyyy").format(date) + " " + formatDay(Calendar.getInstance().get(Calendar.DAY_OF_MONTH));

Passing the day of the month to formatDay and concatenating it with SimpleDateFormat of the month and year is as easy as pie. The result would be something like "April 1st 2023".

Full code explanation for starters

The above code snippet covers the most common method of changing the day of the month to an ordinal indicator using Java. It takes the day of the month as an argument and checks if it's a valid day using Preconditions.checkArgument from Google's Guava library.

Then, it calculates the suffix for the day using switch-case for different conditions. In particular, it covers the edge cases of 11, 12, and 13 — those guys always want to be special, don’t they?

Power-up with advanced tools

Having established the basic method, it's a good time to power up our code by adding advanced features. We are in the 21st century after all, and reusability and localization are the norms. By creating a static suffix array, we can provide localization support for different ordinals and improve the ease of usage.

Additionally, java.time and DateTimeFormatterBuilder bring modern date-time formatting to our rescue, making it possible to elevate the handling of ordinals to a new level. Moreover, remember to stay updated with Google Guava library's updates. Not just for stalking, but for getting any potential bug fixes or performance improvements.

Modern style date formatting

Java developers who want to stay at the top of their game might tap into the rich features of the java.time package. Have a look at this crisp snippet:

public static String formatDayWithJavaTime(LocalDate date) { // It's worth noting that arrays are way cooler than they sound... String[] suffixes = { "th", "st", "nd", "rd", "th", "th", "th", "th", "th", "th" }; int day = date.getDayOfMonth(); String suffix = (day >= 11 && day <= 13) ? "th" : suffixes[day % 10]; DateTimeFormatter formatter = new DateTimeFormatterBuilder() .appendText(ChronoField.DAY_OF_MONTH) .appendLiteral(suffix) .appendPattern(" MMMM yyyy") .toFormatter(); return date.format(formatter); }

With the usage of java.time.LocalDate and the customized DateTimeFormatterBuilder, the snippet above achieves the challenging task of appending ordinal indicators. You surely wouldn’t find a better combination of modern Java APIs, conciseness, and accuracy.

The importance of unit testing

Don't ignore the power of unit testing. Verifying our date formatting code is as important as making a good coffee (trust me, it's VERY important). An example of a unit test for the ordinal day formatter method would look like this:

@Test public void testOrdinalDayFormatter() { assertEquals("1st", formatDay(1)); assertEquals("2nd", formatDay(2)); assertEquals("3rd", formatDay(3)); // No edge is left uncovered... assertEquals("11th", formatDay(11)); assertEquals("12th", formatDay(12)); assertEquals("13th", formatDay(13)); assertEquals("21st", formatDay(21)); // You get the idea... }