You are here

Date ordinals: An ugly solution to an ugly problem

Submitted by cafuego on 14 August, 2012 - 18:36

A friend bumped into what appears to be a very irritating problem yesterday with the PHP date_format() function, which is used by format_date() to show date and time strings on Drupal. This function uses the "S" format character, which returns the english ordinal number suffix for the current day of the month. E.g: "st" on the first day, "nd" on the second day, and so on. (And the date() function does too, coincidentally)

The problem is that when you're working in a non-english locale, the ordinal suffixes returned remain the english ones. Oops.

I thought that this should not be a very hard problem to fix, so I dug through the PHP code a little and found that the "S" format character is hard-coded to use output from the internal english_suffix() function. As that function name implies, there is no provision for using non-english ordinal number suffixes in PHP. Ugh!

Undeterred I decided that this was fixable via an LD_PRELOAD hack, but since the english_suffix() function is not compiled into a library, but into the PHP core, that appears to not actually work. (I may be wrong, but my C-fu is pretty weak and I am happy to be corrected about this - povided you also supply working code ;-)

Some more googling turned up the rename_function() function that's built right into PHP itself. It requires the APD PECL module, which is less than ideal but a not insurmountable problem. However, the APD module won't compile for PHP 5.3 and so I kept on googling.

The next possible solution was runkit_function_rename() which is provided via the Runkit PECL library. Now Runkit also didn't compile, but I found that someone had done a bit of work to port it forward and put the  result at https://github.com/zenovich/runkit and that module compiles fine :-)

The result is a little library file that provides date_format() and date() functions that takes an optional third parameter containing a valid locale string. If this parameter is empty, the current system locale will be used.

The replacement functions use "magic name" callbacks to translate a number into an ordinal suffix for a given language, so you can easily add your own. The snippet of code below will let you have a play after you build, enable and configure the Runkit PECL extension from github:

<?php
  require_once('date_patch.inc');

  setlocale(LC_TIME, 'fi_FI.UTF-8');

  print date('jS F');
  print date('jS F', NULL, 'fr_FR.UTF-8');

  $date_time = date_create('@' . time());
  print date_format($date_time, 'jS F');
  print date_format($date_time, 'jS F', 'fi_FI.UTF-8');
?>

Success of sorts! Yay! (But hnnngg!)

AttachmentSize
Plain text icon date_patch.inc_.txt5.1 KB