Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

PHP date format with intl-aware day suffix?

Sorry if this is a dupe - lots of similar questions but obviously if I could find an exact answer I wouldn't be asking :)

Note I'm coming from .Net and am a PHP newbie, so there may be noob-scale errors.

I would like to be able to output e.g. new DateTime('2014-01-01 13:15:00') as: 'Wednesday the 1st of January 2014 at 1:15PM' (possible - non-localized) or 'Mercredi 1er Janvier 2014 à 13h15' (not possible?).

Basically, there seems to be no ISO formatting equivalent to PHP's 'S' date format specifier, nor is there one for strftime?

The IntlDateFormatter::FULL comes close - but 'Wednesday, 1 January' or 'mercredi 1 janvier' is not good English (or French) - but it seems to be the closest that I can get? I could live without the 'on', 'the' and 'at' if I had to, but ordinal suffixes would be nice. ('Wednesday one January' - what's that, the beginning to a poem?)

I did see one example on the strftime section comments on PHP.net addressing this issue (which seems to suggest that it is an issue) - however it only seemed to add the English suffixes, which didn't seem much use? I'd like a simple method that takes a UTC datetime, a locale and a timezone and outputs a localized string - preferably in 'proper' human-readable format (as above) as is possible in English. I'd like to achieve this without writing a format string for every language in the world. It would also be nice if it worked on my Windows dev box as well as the *nix production box.

<?php
$utcdate = new DateTime('2014-01-01 13:15:00', new DateTimeZone('UTC'));
echo $utcdate->format('l \t\h\e jS \o\f F Y \a\t g:ia') . "<br>";
function dumpDates($date, $locale, $tz){
    $date->setTimeZone(new DateTimeZone($tz));
    $fmt = new IntlDateFormatter( $locale, IntlDateFormatter::FULL, IntlDateFormatter::FULL,
         $tz, IntlDateFormatter::GREGORIAN  );
    echo $fmt->format($date) . "<br>";
    // doesn't work under windows?
    setLocale(LC_TIME, $locale);
    echo strftime('%A, %#d %B %Y %I:%M:%S %p', $date->getTimeStamp()) . "<br>";

}
dumpDates($utcdate, 'en_GB', 'Europe/London');
dumpDates($utcdate, 'de_DE', 'Europe/Berlin');
dumpDates($utcdate, 'fr_FR', 'Europe/Paris');
?>
like image 274
justageezer Avatar asked Nov 10 '22 09:11

justageezer


1 Answers

The full part of this question - including full grammatical legibility - would be very difficult to do without either, as you say, writing a format string for every language in the world, or finding a library that contains such strings. MomentJs seems to provide great intl support, but after a cursory search, I haven't been able to find a PHP equivalent, other than the intl extension.

You could get to the stage of providing an internationalised form including ordinal-based number by using a combination of IntlDateFormatter and NumberFormatter, by first using NumberFormatter to get the pattern for the date's ordinal suffix/prefix:

$numFmt = new NumberFormatter('fr_FR', NumberFormatter::ORDINAL);
$ordinalDay = $numFmt->format($date->format('j'));

You could then create a IntlDateFormatter that allows you to retrieve the pattern for the Full date format of the target language:

$dateFormat = new IntlDateFormatter('fr_FR', IntlDateFormatter::FULL, IntlDateFormatter::FULL, $tz, IntlDateFormatter::GREGORIAN);
$datePattern = $dateFormat->getPattern();

Finally, you would need to replace the section in the $datePattern representing the day with the escaped ordinal day pattern:

$datePattern = preg_replace('/d+', "'"+$ordinalDay+"'", $datePattern);
$dateFormat->setPattern($datePattern);
$outputDate = $dateFormat->format($date);   

Note that the pattern used by IntlDateFormatter is different from the usual PHP date formatting format codes, here is the documentation for the codes recognised.

A warning; in internationalised formats that are fairly rigidly standardized, an ordinal number would look out of place. For example in chinese, the format is:

y年M月d日EEEE

and inserting the ordinal prefix that exists for written Chinese before the day value may look odd to a Chinese reader.

like image 67
Benjamin Avatar answered Nov 15 '22 08:11

Benjamin