Localized Date Formats in WordPress

We recently added a new date column in picu to show the “Last Modified” date when a collection was last changed, instead of the usual post-date, that showed when a collection was created.

In a first iteration we used the date_i18n() and wp_date() functions to format the date.

While this worked ok, it always gave us the date in the date-format that we specified in the function. It handled timezones as well, which is nice, but we wanted the format to be localized as well.

The first idea that I found somewhere on Stackoverflow (I think), was to use the sites date_format setting, which I thought made sense. A call like this:

wp_date( get_option( 'date_format' ), $date );Code language: PHP (php)

Would give you the date formatted in the way that is set in the site settings, in my case it would output something like:

08. März 2023Code language: plaintext (plaintext)

But when checking the post-list views from core, I realized that they didn’t look the same and use yet another format which uses less space in the table. It looked more like this:

08.03.2023Code language: plaintext (plaintext)

So I looked into how it’s done in core, and found this (in /wp-admin/includes/class-wp-posts-list-table.php:1160):

$t_time = sprintf(
    /* translators: 1: Post date, 2: Post time. */
    __( '%1$s at %2$s' ),
    /* translators: Post date format. See https://www.php.net/manual/datetime.format.php */
    get_the_time( __( 'Y/m/d' ), $post ),
    /* translators: Post time format. See https://www.php.net/manual/datetime.format.php */
    get_the_time( __( 'g:i a' ), $post )
);Code language: PHP (php)

The trick here is that the $format set in wp_date() or get_the_time() is using a translatable string __( 'Y/m/d' ) to specify the format of the date. Because this string is already used and translated in WordPress core, we can use it without our own textdomain and get it translated “for free”. 1 See Update below

wp_date( __( 'Y/m/d', 'your-textdomain' ), $date );Code language: PHP (php)

The rest of the function is used to also get the time and make the whole string fully translatable. So, the final function that we use right now, looks like this:

$post_modified = sprintf(
    __( '%1$s at %2$s' ),
    wp_date( __( 'Y/m/d', 'your-textdomain' ), $date ),
    wp_date( __( 'g:i a', 'your-textdomain' ), $date )
);Code language: PHP (php)

In the end, this gives us a fully translatable date which is also shown in the right format based on the locale in use, if a translation is found. To get the correct formats, you need to duplicate the original translated strings from WordPress core to your plugins translation. Here’s a few examples of how this might look like in different locales:

// German (Switzerland) – de_CH
08.03.2023 um 16:00 Uhr

// English – en_US
2023/03/08 at 4:00 pm

// French (France) – fr_FR
08/03/2023 à 16h00

// Spanish – es_ES
09/03/2023 a las 16:00Code language: plaintext (plaintext)

Beautiful 🤩

  1. Update 2023-03-13: As Torsten Landsiedel pointed out correctly, using strings from WordPress core directly in your plugin without a text-domain is discouraged, as those strings could change in the future. It’s always good to follow best practices wherever possible, so I updated this post and the code examples to make use of a text-domain. Thanks for the heads up, Thorsten! ↩︎

Made with ❤️ in Switzerland