Number::ordinal

Converts a number to its ordinal form, turning 1 into 1st and 11 into 11th.

Signature
Number::ordinal(int|float $number, ?string $locale = null): string
  • Added in Laravel 10.33.0

Parameters

ParameterTypeDescription
$$numberint|floatThe value to convert.
$$localeoptional?string= nullICU locale supplying the ordinal rules. Falls back to the Number class locale.

Return value

stringThe number with its locale-appropriate ordinal indicator, such as '21st'.

Errors

Throws RuntimeException when the intl PHP extension is not loaded.

Changelog

  • PHP 10.33.0Introduced together with the Illuminate\Support\Number class.

Number::ordinal() hands the value to ICU's ordinal formatter, so you get 1st, 2nd, 3rd, 4th and — the part people get wrong when they write this by hand — 11th, 12th and 13th rather than 11st, 12nd and 13rd. The rule is not "look at the last digit"; ICU already knows that, which is the main reason to call this instead of a switch statement.

Digits, not words

The output keeps the numeral and appends an indicator. If you want twenty-first, that is Number::spellOrdinal.

Locale changes the shape entirely

The indicator is locale-specific, not a universal st/nd/rd/th set. German ordinals are written 1., French uses 1er then 2e, and some locales have gendered forms that a single string cannot express. Do not concatenate the result with an English word and assume it reads correctly elsewhere; translate the whole phrase instead.

Because it builds a NumberFormatter, this method requires the intl extension like the rest of the locale-aware helpers.

Example

Try it yourself
Loading editor…
Press Run to execute the code.

When to use it

  • Labelling a leaderboard position as 3rd place
  • Rendering 'your 2nd invoice this month' in a notification
  • Writing day-of-month labels such as 21st in a schedule

Frequently asked questions

Does Number::ordinal handle 11th, 12th and 13th correctly?

Yes. It uses ICU's ordinal rules rather than looking at the last digit, so 11, 12 and 13 come out as 11th, 12th and 13th, and 111 as 111th — the exact cases a hand-written match statement gets wrong.

How do I get 'first' instead of '1st'?

Use Number::spellOrdinal(), added in Laravel 11.34, which spells the ordinal out as words. Number::ordinal() always keeps the numeral and appends an indicator.

Why does Number::ordinal return '1.' on my server?

The Number class locale has been changed, most likely by a Number::useLocale() call in a service provider. German and several other locales write ordinals as a numeral followed by a period. Pass the locale explicitly if you need the English form.

More examples

Why the naive version is wrong

The naive column produces 11st, 12nd, 13rd and 111st. Number::ordinal() gets 11th, 12th, 13th and 111th right because ICU encodes the teens exception. This is the single most common home-grown ordinal bug.

Example · php
<?php

use Illuminate\Support\Number;

function naiveOrdinal(int $n): string
{
    return $n.match ($n % 10) {
        1 => 'st',
        2 => 'nd',
        3 => 'rd',
        default => 'th',
    };
}

foreach ([1, 11, 12, 13, 21, 111, 112] as $n) {
    printf("%-5s naive: %-6s ordinal(): %s\n", $n, naiveOrdinal($n), Number::ordinal($n));
}

Ordinals across locales

English gives 1st, 2nd, 11th; German gives 1., 2., 11.; French gives 1er, 2e, 11e. The suffix is not a decoration you can bolt onto any language, which is why the whole phrase — not just the number — belongs in your translation files.

Example · php
<?php

use Illuminate\Support\Number;

foreach (['en', 'de', 'fr', 'it', 'nl'] as $locale) {
    printf("%-3s %s  %s  %s\n",
        $locale,
        Number::ordinal(1, $locale),
        Number::ordinal(2, $locale),
        Number::ordinal(11, $locale)
    );
}

A date label without a DateTime format

Prints 'Renews on the 21st of March'. Carbon's own 'S' format token would also produce the suffix, but building the phrase from ordinal() lets you place the day anywhere in a translated sentence instead of being tied to a format string.

Example · php
<?php

use Illuminate\Support\Carbon;
use Illuminate\Support\Number;

Carbon::setTestNow('2026-03-21 09:00:00');

$date = Carbon::now();

printf(
    "Renews on the %s of %s\n",
    Number::ordinal($date->day),
    $date->format('F')
);

Discussion

  • Be the first to comment on this lesson.