Updating Deprecated strftime() to IntlDateFormatter for Date/Time Formatting

Updating Deprecated strftime() to IntlDateFormatter for Date/Time Formatting
Updating Deprecated strftime() to IntlDateFormatter for Date/Time Formatting

Learn how to replace the deprecated strftime() function in PHP with the modern IntlDateFormatter. This tutorial covers why strftime() was deprecated, how to migrate your code, and the benefits of using IntlDateFormatter for date and time formatting, including localization and custom formats.

You upgrade to PHP 8.1, reload the app, and the logs start filling up: Function strftime() is deprecated. That function has formatted dates in PHP for decades, and now it’s on its way out. Here’s why, and exactly what to move to.

Why Was strftime() Deprecated in PHP 8.1?

strftime() leans on the operating system’s locale, set through setlocale(). That sounds convenient until you deploy. The same code prints one thing on your Mac, something else on the Linux box, and breaks outright on a server where the locale isn’t even installed. It also isn’t reliably UTF-8 safe, so accented month names and non-Latin scripts come back mangled.

Those weren’t bugs you could patch. They were baked into how the function worked, so PHP 8.1 deprecated strftime() and its UTC sibling gmstrftime() together. They still run today, but they’re marked for removal, so treat every warning as a task, not noise.

You have two replacements, and picking the right one matters:

  • date() or DateTime::format() when the output isn’t localized: logs, filenames, machine-readable timestamps. No extra extension, no fuss.
  • IntlDateFormatter (from the intl extension) when a human reads the date and the language matters. It’s locale-aware and Unicode-safe.

Most of the pain with strftime() was the localized case, so that’s where the rest of this focuses.

Transitioning from strftime() to IntlDateFormatter

The old way with strftime()

Here’s the kind of code you’re replacing:

PHP
<?php
$date = strtotime('2023-09-01');
echo strftime("%B %d, %Y", $date);  // Output: September 01, 2023

Full month name, day, year. Clean output, right up until PHP throws the deprecation warning and, eventually, drops the function entirely.

The same thing with IntlDateFormatter

Before you touch the code, unlearn one habit: IntlDateFormatter does not use strftime()‘s %B %d %Y codes. It uses ICU pattern tokens, a different alphabet. Copy your old format string across and it won’t work.

PHP
<?php
$date      = strtotime('2023-09-01');
$formatter = new IntlDateFormatter('en_US', IntlDateFormatter::LONG, IntlDateFormatter::NONE);
echo $formatter->format($date);  // Output: September 1, 2023

We ask for the US English locale, a LONG date, and NONE for the time, so we get the date on its own. Notice the day: it prints “September 1”, not “September 01”. The predefined styles follow each locale’s conventions, padding and all, and that’s the whole point.

Switching locales

Change the locale string and the formatting follows. French:

PHP
<?php
$date      = strtotime('2023-09-01');
$formatter = new IntlDateFormatter('fr_FR', IntlDateFormatter::LONG, IntlDateFormatter::NONE);
echo $formatter->format($date);  // Output: 1 septembre 2023

Same code, French conventions: day first, lowercase month, no comma. This is the reason to reach for intl in the first place.

Adding the time

Want date and time together? Set a time style instead of NONE:

PHP
<?php
$date      = strtotime('2023-09-01 14:30:00');
$formatter = new IntlDateFormatter('en_US', IntlDateFormatter::LONG, IntlDateFormatter::SHORT);
echo $formatter->format($date);  // Output: September 1, 2023, 2:30 PM

LONG for the date, SHORT for the time. One heads-up: the exact separator between them (“at” versus a comma) shifts with your ICU version, so don’t assert on a hard-coded string in tests.

Handling Custom Date Formats

The predefined styles cover most cases. When you need an exact layout, set an ICU pattern yourself:

PHP
<?php
$date      = strtotime('2023-09-01 14:30:00');
$formatter = new IntlDateFormatter('en_US', IntlDateFormatter::NONE, IntlDateFormatter::NONE);
$formatter->setPattern('MMMM d, yyyy, h:mm a');
echo $formatter->format($date);  // Output: September 1, 2023, 2:30 PM

MMMM is the full month, d the un-padded day, yyyy the year, h:mm a a 12-hour clock. These are ICU tokens, not strftime() codes, so keep the ICU reference open while you build a pattern. A wrong token tends to fail quietly, printing something plausible but wrong rather than erroring out.

Localization and Internationalization

This is where the switch earns its keep. One codebase, correct dates for every locale you support, without juggling setlocale() calls that fight each other across a single request.

Working with time zones

Pass a time zone as the fourth constructor argument, or set it later with setTimeZone():

PHP
<?php
$date      = strtotime('2023-09-01 14:30:00');
$formatter = new IntlDateFormatter('en_US', IntlDateFormatter::LONG, IntlDateFormatter::SHORT, 'America/New_York');
echo $formatter->format($date);  // Output: September 1, 2023, 2:30 PM EDT

Read this one slowly, because it trips people up. A timestamp is an absolute moment. The formatter’s time zone only decides how that moment is displayed; it does not move the clock. strtotime('2023-09-01 14:30:00') is parsed in your default time zone (date_default_timezone_get()), so if that default is UTC, this same code prints 10:30 AM in New York, not 2:30 PM. Set your default time zone deliberately and the guesswork disappears.

One more catch: the SHORT time style doesn’t include the zone name. If you actually want “EDT” in the output, use a LONG or FULL time style, or add a zone token to a custom pattern.

Common pitfalls when migrating
  • Time zone assumptions: know how your input timestamp was created before you trust the displayed time.
  • Locale strings: a wrong or missing locale falls back silently, and you only notice the off output if you read the language.
  • ICU patterns: they aren’t strftime() codes. One wrong token gives you plausible-but-wrong output, not an error.
Wrapping up

strftime() served its time, but system-locale dependence and shaky Unicode support made it a liability. For machine output, reach for date() or DateTime::format(). For anything a person reads in their own language, IntlDateFormatter is the reliable pick. Clear the deprecation warnings now, while they’re still warnings and not fatal errors on the next major upgrade.

Leave a Comment

Your email address will not be published. Required fields are marked *


Scroll to Top