Back to Projects & Articles
Web DevMaths & AlgorithmsEduTech

Generating Well Formatted Ordinal Suffixes

I’ve got no plans on the 25st

Jun 5, 2024
3 min read
16 Medium claps
A monthly planner Photo inspired by Estée Janssens on Unsplash
A monthly planner — Photo inspired by Estée Janssens on Unsplash

Handling dates, whether in code or even in a PowerPoint presentation, can be surprisingly tricky. Even the way we read dates aloud is peculiar — we instinctively add the word “the” and “of” even though they are not written: “Today is Wednesday the 5th of June.”

As a teacher, I’m particular about how dates appear in my materials. It bothers me when the ordinal indicators (st, nd, rd, th) are missing, which often happens when dates are automatically inserted into slides.

The Quirk of Dates and the Quest for Clarity

As we encounter dates on our computers and across the web, we humans are generally adept at deciphering the numbers and slashes to determine the actual date. Here in the UK, we’re unphased by the US format of placing the month first — for instance, seeing “6/5/2024” on my Windows taskbar and understanding it’s not the 6th of May.

However, I’m currently developing a website where I want the date displayed exactly as I’d write it on my classroom whiteboard. A simple “Wednesday 5 June” won’t cut it.

JavaScript Function to Create Ordinal Numbers

ordinalSuffix.js
1const getOrdinalSuffix = (inputNumber) => {
2 const ordinalSuffixes = ["th", "st", "nd", "rd"];
3 const lastTwoDigits = inputNumber % 100;
4 return (
5 inputNumber +
6 (ordinalSuffixes[(lastTwoDigits - 20) % 10] ||
7 ordinalSuffixes[lastTwoDigits] ||
8 ordinalSuffixes[0])
9 );
10};

Interactive Ordinal Suffix Tester

Live Evaluator
Quick test:
Standard Ordinal Output
5th
Whiteboard Superscript (<sup>)
5th(e.g., Wednesday 5th June)
Evaluation trace for inputNumber = 5:
• lastTwoDigits: 5 % 100 = 5
• Attempt 1: (lastTwoDigits - 20) % 10 = (5 - 20) % 10 = -5 → undefined (fails)
• Attempt 2: ordinalSuffixes[5] → undefined (fails)
• Result: Selected suffix → “th”

How the Logic Works:

  1. Setting Up the Suffixes:

    ordinalSuffixes = ["th", "st", "nd", "rd"];: This array stores the four possible ordinal suffixes in English.

  2. Finding the Relevant Digits:

    lastTwoDigits = inputNumber % 100;: The modulo operator (%) calculates the remainder when inputNumber is divided by 100. This gives us the last two digits of the number, which are the key to determining the suffix.

    For example, if inputNumber is 123, lastTwoDigits will be 23.

  3. Adjusting for Special Cases (11, 12, 13):

    (lastTwoDigits - 20) % 10: This calculation addresses the special cases where numbers ending in 11, 12, or 13 use “th” instead of the usual pattern.

    If lastTwoDigits is between 11 and 13 (inclusive), this calculation results in a negative number or zero, which fails the first lookup and falls through cleanly.

  4. Selecting the Correct Suffix:

    ordinalSuffixes[(lastTwoDigits - 20) % 10] || ordinalSuffixes[lastTwoDigits] || ordinalSuffixes[0]: This part is the core logic for selecting the suffix:

    • First Attempt: It tries to access the suffix using (lastTwoDigits - 20) % 10 as the index. If lastTwoDigits is 21, 22, 23, or 31, this evaluates to 1, 2, or 3, giving the correct index for “st”, “nd”, or “rd”.
    • Second Attempt (Fallback): If the first attempt fails (because the index is out of bounds or points to undefined), it tries to access the suffix directly using lastTwoDigits. This handles single-digit numbers (1st, 2nd, 3rd).
    • Default: If both previous attempts fail, it defaults to ordinalSuffixes[0], which is “th”. This handles numbers ending in 0, 4, 5, 6, 7, 8, or 9, as well as 11, 12, and 13.
  5. Returning the Ordinal Number:

    inputNumber + (...): Finally, the original inputNumber is combined with the selected suffix using string concatenation (+), and the resulting ordinal number (e.g., “21st”) is returned.

Trace Example (inputNumber = 22):
• lastTwoDigits becomes 22
• (lastTwoDigits - 20) % 10 becomes 2
• ordinalSuffixes[2] is "nd"
• Function returns "22nd"

Next step — superscript to the rescue

Having generated the correct ordinal suffix, the next step is to refine the presentation. After all, a well-formatted date should not only be accurate but also visually pleasing. It irks me when these ordinal indicators are not presented correctly, so this means ensuring the letters are small and raised, just as we’d write them on a whiteboard.

The below tweak builds this in with the <sup> HTML tag:

ordinalSuperscript.js
1const getOrdinalSuffix = (inputNumber) => {
2 const ordinalSuffixes = ["th", "st", "nd", "rd"];
3 const lastTwoDigits = inputNumber % 100;
4
5 // Select the correct suffix and wrap it in <sup> tags
6 const suffix =
7 ordinalSuffixes[(lastTwoDigits - 20) % 10] ||
8 ordinalSuffixes[lastTwoDigits] ||
9 ordinalSuffixes[0];
10
11 const superscriptSuffix = `<sup>${suffix}</sup>`;
12
13 // Combine the input number and superscripted suffix
14 return `${inputNumber}${superscriptSuffix}`;
15};

As someone with a mild case of typographical OCD, seeing those letters not raised and reduced in size is the digital equivalent of nails on a chalkboard. Hopefully, this exploration into the intricacies of date formatting has been as enlightening for you as it’s been therapeutic for me!