skip to content

PHP: International Date Formatter

If you've just landed here it's probably because you found out that the PHP strftime function has been deprecated in PHP 8.1 meaning you have to instead use the IntlDateFormatter class for locale-specific output - which looks complicated.

Installing the module

For apache there is a package php-intl which can be installed from the command-line as follows:

# apt -u install php-intl

This will actually install a version of the package relevant to your PHP installaction. For example php7.4-intl if you are running PHP 7.4.

After installation you will need to reload the Apache configuration to make the module and its functions available in PHP:

# apachectl graceful

Now you are ready to start using the IntlDateFormatter class.

Formatting dates with strftime

Until now we've been using something like the following to format international date strings (for local dates the date function suffices):

<?PHP $timestamp = strtotime('11 November 2023 11:12:00'); echo strftime('%c', $timestamp),"<br>\n"; echo strftime('%e %B %Y', $timestamp),"<br>\n"; echo strftime('%H:%M:%S', $timestamp),"<br>\n"; echo strftime('%A', $timestamp),"<br>\n"; ?>

These and other formatting codes can be found on the PHP manual page for strftime.

which will output the following:

Sat Nov 11 11:12:00 2023 11 November 2023 11:12:00 Saturday

And by adding a simple command to change the locale:

<?PHP setlocale(LC_TIME, 'nl_NL'); ?>

we can change the output to be language-specific:

za 11 nov 2023 11:12:00 AEDT 11 november 2023 11:12:00 zaterdag

Switching to IntlDateFormatter

The major change is that rather than a single line we now have to first define a 'formatter' before we can apply it to our timestamp:

<?PHP $datefmt = datefmt_create( 'en_GB', \IntlDateFormatter::$dateType, \IntlDateFormatter::$timeType, 'Europe/London', \IntlDateFormatter::GREGORIAN ); echo datefmt_format($datefmt, time()); ?>

In the folllowing table $timeType has been set to \IntlDateFormatter::FULL while we experiment with different values for $dateType:

dateType output
FULLFriday, 24 May 2024 at 15:33:32 British Summer Time
LONG24 May 2024 at 15:33:32 British Summer Time
MEDIUM24 May 2024, 15:33:32 British Summer Time
SHORT24/05/2024, 15:33:32 British Summer Time
NONE15:33:32 British Summer Time

And here $dateType has been set to \IntlDateFormatter::FULL while we experiment with different values for $timeType:

timeType output
FULLFriday, 24 May 2024 at 15:33:32 British Summer Time
LONGFriday, 24 May 2024 at 15:33:32 BST
MEDIUMFriday, 24 May 2024 at 15:33:32
SHORTFriday, 24 May 2024 at 15:33
NONEFriday, 24 May 2024

More exotic IntlDateFormatter values are available where relative values of 'yesterday', 'today' and 'tomorrow' are returned where appropriate. There is also the option of using non-Gregorian ('TRADITIONAL') calendars.

You can see from the above how to get a formatted time string in a given location ('Europe/London') and language ('en_GB') for a supplied timestamp in a range of short and long formats.

But this isn't quite what we were after as we want to be able to define our own date formats such as 'yyyy-mm-dd' or 'mm/dd/yyyy'. That is also possible, it just requires an extra 'pattern' parameter.

Custom date strings

The date formatting symbols for IntlDateFormatter are different from those you might have used for the PHP date or strftime commands.

Instructions and some examples can be found in the ICU User Guide which applies to several programming languages.

Here you can find some examples that may be useful:

pattern output
yyyyMMdd hh:mm:ss z20240524 03:33:32 BST
EEEE BBBBFriday in the afternoon
MMMM d 'at' h:mm aMay 24 at 3:33 pm
yyyy.MM.dd G 'at' HH:mm:ss zzz2024.05.24 AD at 15:33:32 BST

In each case we are preparing the date formatter using:

<?PHP $datefmt = datefmt_create( 'en_GB', \IntlDateFormatter::NONE, \IntlDateFormatter::NONE, 'Europe/London', \IntlDateFormatter::GREGORIAN, $pattern ); echo datefmt_format($datefmt, time()); ?>

While you're working with IntlDateFormatter you should be aware that it's possible both to re-use and to re-define your formatter with methods such as datefmt_set_timezone and datefmt_set_pattern on an existing format.

PHP Class for formatting dates

To make things easier, we've whipped up a simple PHP class that can be used for converting timestamps into properly formatted dates using the IntlDateFormatter class:

<?PHP namespace Chirp; class DateFmt { // Original PHP code by Chirp Internet: // Please acknowledge use of this code by including this header. protected $datefmt; public function __construct(string $locale = NULL, string $timezone = NULL) { $this->datefmt = datefmt_create( $locale ?? locale_get_default(), \IntlDateFormatter::NONE, \IntlDateFormatter::NONE, $timezone ?? date_default_timezone_get(), \IntlDateFormatter::GREGORIAN, ); } public function format(int $timestamp, string $pattern) : string { datefmt_set_pattern($this->datefmt, $pattern); return datefmt_format($this->datefmt, $timestamp); } }

The above DateFmt class can be invoked as follows;

<?PHP $datefmt = new \Chirp\DateFmt("en_US", "America/New_York"); echo $datefmt->format(time(), "d MMMM YYYY"); echo $datefmt->format(time(), "HH:mm:ss z"); echo $datefmt->format(time(), "EEEE BBBB"); ?> 24 May 2024 10:33:32 EDT Friday in the morning

And for a different location and language (locale):

<?PHP $datefmt = new \Chirp\DateFmt("ro_RO", "Europe/Bucharest"); echo $datefmt->format(time(), "d. MMMM YYYY"); echo $datefmt->format(time(), "HH:mm:ss z"); echo $datefmt->format(time(), "EEEE BBBB"); ?> 24. mai 2024 17:33:32 EEST vineri după-amiaza

You'll seem from the code that if you don't supply a locale and timezone then your system default settings will be used instead.

In the examples we're passing the current time (time()), but this can be replaced by any timestamp, and you can convert date strings into timestamps using strtotime.

If you've found this article useful, or think there's someone we've missed, let us know using the feedback form below.

  • PHP International Date Formatter


User Comments

Post your comment or question

23 September, 2023

Hey, I just wanted to say thanks for this Intl Date Formatter article. The explanations I found elsewhere were way over my head. I finally got it to work. The strftime method was definitely more straightforward.

I noticed you set "IntlDateFormatter" to "NONE" for both the date and time; I assume that's because a custom pattern is used?

Sidenote: It's a bummer you can no longer set am/pm in lowercase with this new technique. You need to force it by coding it like 'aaaaa\'m\'


$Pattern='MMMM d, y \'at\' h:mmaaaaa\'m\';

That's progress, I guess.