Date ordinals: An ugly solution to an ugly problem
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 date_patch.inc_.txt5.1 KB
Tags: php5drupalrunkitpeclinternational