Locale-Sensitive Dates in PHP
In particular I needed dates like “Donderdag 23 Oktober”, and I was sure PHP should know how to do this without me creating arrays for days of the week and months of the year. With some help from my friend (thanks Derick) I discovered that there is a date function in PHP that takes into account the locale of the script, called strftime. The machine needs to have the locale already installed, then you can just do:
setlocale(LC_TIME, 'nl_NL.UTF-8');
return ucwords(strftime('%A %e %B',$publish_date));
Setlocale() will return false if the language isn’t available on the host system, so its possible to check and maybe try a few likely ones or let the user know. This was useful to me and will work for other languages too – you just need the locale installed and then set with setlocale.
be very careful with setlocale, read the warning on the php.net page about it and also the comment from the dutch user on 09-Sep-2002 04:02.
Hmm… I think Zend_Date with Zend_Locale maybe usefull here :)
Regards
We may also supply array as argument to avoid if our locale ID doesn’t exist, so php attempt to use another id. Because sometime the locale ID is different between OS.
Just like what I did on my blog which is only for Indonesian audiences.
[geshi lang=php]
setlocale(LC_TIME, array(‘id_ID’, ‘id’, ‘ind’));
[/geshi]
Seems like everyone is into hint-dropping today instead of actual advice. Maarten’s warning is a good one, and refers to http://uk2.php.net/manual/en/function.setlocale.php#25041 where a dutch user had his floating point numbers get mangled going in to mysql because of the differing decimal separator.
Michal: Interesting hint – this is a Zend Framework project so I might follow up on that. Any resources or examples would be helpful, but I will also rummage so many thanks for mentioning this.
Firman: The idea of using an array is excellent advice – quite a few people have recommended that I do this since I wrote this post. Thanks for adding your comment :)
Resources- obviously ZF Documentation :)
1. “Zend_Date”:http://framework.zend.com/manual/en/zend.date.html
2. “Zend_Locale_Date”:http://framework.zend.com/manual/en/zend.locale.date.datesandtimes.html
And short example of using Zend_Date with Zend_Locale
[geshi lang=php]
// setting default timezone
date_default_timezone_set(‘Europe/Warsaw’);
// setting locale according to users`s browser
$locale = new Zend_Locale(Zend_Locale::BROWSER);
// creating Zend_Date object AND passing locale object
$date = new Zend_Date(‘2008-11-03 18:34:40’,null,$locale);
// outputting date with given format
echo $date->toString(‘EEEE, d MMMM YYYY’);
[/lang]
For polish the output will be: “poniedziałek, 3 listopada 2008, 18:34” and for Dutch: “maandag, 3 november 2008, 18:34”
The coolest part is that Zend_Locale supplies your app not only with localized names of months, years, and so on, but also with bunch of date formats widely used in different countries :)
Regards
Great article Lorna. Welcome to strftime() ;-)
To take Maarten’s warning one step further:
The issue he is refering to is using set_locale() with LC_ALL as the category which is not just inconvenient/confusing with the floating point numbers, but can actually be very dangerous if some of your variable validation code uses CTYPE functions as CTYPE is locale aware as well.
Lorna’s example code where she sets locale specifically for the LC_TIME category *only* however is spot on and will avoid these problems.
Michal, Juliette: Thanks for both adding those words of wisdom from your experiences of correctly using non-English languages successfully. I’m now much better informed :)
So I refactored a bit with Zend_Date and Zend_Locale, and got a much nicer result. Follow-up blog post in the pipeline with the example (all 3 lines of it!)