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 |
---|---|
FULL | Tuesday, 8 October 2024 at 14:17:48 British Summer Time |
LONG | 8 October 2024 at 14:17:48 British Summer Time |
MEDIUM | 8 Oct 2024, 14:17:48 British Summer Time |
SHORT | 08/10/2024, 14:17:48 British Summer Time |
NONE | 14:17:48 British Summer Time |
And here $dateType has been set to \IntlDateFormatter::FULL while we experiment with different values for $timeType:
timeType | output |
---|---|
FULL | Tuesday, 8 October 2024 at 14:17:48 British Summer Time |
LONG | Tuesday, 8 October 2024 at 14:17:48 BST |
MEDIUM | Tuesday, 8 October 2024 at 14:17:48 |
SHORT | Tuesday, 8 October 2024 at 14:17 |
NONE | Tuesday, 8 October 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 z | 20241008 02:17:48 BST |
MMMM YYYY | October 2024 |
MM/dd/yyyy | 10/08/2024 |
yyyy-MM-dd | 2024-10-08 |
EEEE BBBB | Tuesday in the afternoon |
MMMM d 'at' h:mm a | October 8 at 2:17 pm |
yyyy.MM.dd G 'at' HH:mm:ss zzz | 2024.10.08 AD at 14:17:48 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: www.chirpinternet.eu
// 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");
?>
8 October 2024
09:17:48 EDT
Tuesday 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");
?>
8. octombrie 2024
16:17:48 EEST
marți 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.
Related Articles - Date and Time
- PHP International Date Formatter
Tomcat76 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\'
Example:
$Pattern='MMMM d, y \'at\' h:mmaaaaa\'m\';
That's progress, I guess.