PHP - locale specific date format for English and French - php

Locale specific dates present an interesting problem, not only do we need to specify the appropriate translation (Ex: September=>septembre) but we also need to ensure the format is in the right order (Ex: September 15, 2018=>15 septembre 2018)
PHP's date function date() is English only, so that can be immediately disregared.
Instead, my "research" has pointed me to strftime(). I prepared the following code: echo strftime('%b %e, %Y',strtotime($date));
This outputs: May 1, 2018 and mai 1, 2018. This seemed to solve the issue, that is until we had our bilingual testers identify that the days should be formatted 1 mai 2018.
What is the best way of dealing with this, is it a static class? I want to prepare our solution following best practices, but I have not found the answer.
class LocaleDate
{
public static function date($date)
{
$locale = setlocale(LC_ALL, 0);
if ($locale == "fr_CA" || $locale == "fr_CA.UTF-8") {
return strftime('%e %b %Y',strtotime($date));
} else {
return strftime('%b %e, %Y',strtotime($date));
}
}
}
echo LocaleDate::date($date)
Would that be the best way to go about this issue? Needing to identifty the locale and outputting from there? Seems tedious if you have multiple languages to deal with.

Use the DateTime class alongside the IntlDateFormatter.
Example:
<?php
$dt = new DateTime;
$formatter = new IntlDateFormatter('fr_FR', IntlDateFormatter::SHORT, IntlDateFormatter::SHORT);
$formatter->setPattern('E d.M.yyyy');
echo $formatter->format($dt);
Output:
jeu. 17.5.2018
Have a play with it here: https://3v4l.org/tuEM0
Check the documentation here: http://php.net/manual/en/class.intldateformatter.php

Related

PHP 8.1: strftime() is deprecated

When upgrading to PHP 8.1, I got an error regarding "strftime".
How do I correct the code to correctly display the full month name in any language?
$date = strftime("%e %B %Y", strtotime('2010-01-08'))
To my dear and late strftime()... I found a way to adapt with IntlDateFormatter::formatObject and here is the link for the references to the schemas:
https://unicode-org.github.io/icu/userguide/format_parse/datetime/#date-field-symbol-table
... For those who want to format the date more precisely
// "date_default_timezone_set" may be required by your server
date_default_timezone_set( 'Europe/Paris' );
// make a DateTime object
// the "now" parameter is for get the current date,
// but that work with a date recived from a database
// ex. replace "now" by '2022-04-04 05:05:05'
$dateTimeObj = new DateTime('now', new DateTimeZone('Europe/Paris'));
// format the date according to your preferences
// the 3 params are [ DateTime object, ICU date scheme, string locale ]
$dateFormatted =
IntlDateFormatter::formatObject(
$dateTimeObj,
'eee d MMMM y à HH:mm',
'fr'
);
// test :
echo ucwords($dateFormatted);
// output : Jeu. 7 Avril 2022 à 04:56
I've chosen to use php81_bc/strftime composer package as a replacement.
Here the documentation.
Pay attention that the output could be different from native strftime 'cause php81_bc/strftime uses a different library for locale aware formatting (ICU).
Note that output can be slightly different between libc sprintf and this function as it is using ICU.
You can use the IntlDateFormatter class. The class works independently of the locales settings. With a function like this
function formatLanguage(DateTime $dt,string $format,string $language = 'en') : string {
$curTz = $dt->getTimezone();
if($curTz->getName() === 'Z'){
//INTL don't know Z
$curTz = new DateTimeZone('UTC');
}
$formatPattern = strtr($format,array(
'D' => '{#1}',
'l' => '{#2}',
'M' => '{#3}',
'F' => '{#4}',
));
$strDate = $dt->format($formatPattern);
$regEx = '~\{#\d\}~';
while(preg_match($regEx,$strDate,$match)) {
$IntlFormat = strtr($match[0],array(
'{#1}' => 'E',
'{#2}' => 'EEEE',
'{#3}' => 'MMM',
'{#4}' => 'MMMM',
));
$fmt = datefmt_create( $language ,IntlDateFormatter::FULL, IntlDateFormatter::FULL,
$curTz, IntlDateFormatter::GREGORIAN, $IntlFormat);
$replace = $fmt ? datefmt_format( $fmt ,$dt) : "???";
$strDate = str_replace($match[0], $replace, $strDate);
}
return $strDate;
}
you can use format parameters like for datetime.
$dt = date_create('2022-01-31');
echo formatLanguage($dt, 'd F Y','pl'); //31 stycznia 2022
There are extension classes for DateTime that have such functions integrated as methods.
echo dt::create('2022-01-31')->formatL('d F Y','pl');
The strftime is obsolete and DateTime::format() provide a quick replacement and IntlDateFormatter::format() provied a more sophisticated slution.
this links will be help you:
https://github.com/modxcms/revolution/issues/15864
https://github.com/php/php-src/blob/1cf4fb739f7a4fa8404a4c0958f13d04eae519d4/UPGRADING#L379-L381
https://www.php.net/manual/en/datetime.format.php
strftime is deprecated PHP 8.1, You can use date function.
$date = date("%e F Y", strtotime('2010-01-08'))
Hey I have also experienced this issue as well so after some research on PHP's official documentation here what I found!
https://www.php.net/manual/en/function.strftime.php
They are saying that it is depricated and use setlocale() function
this also work same as strftime().
For more information please visit official PHP docs of setlocale() https://www.php.net/manual/en/function.setlocale.php
A quick and simple replacement for the deprecated function strftime can be following.
Instead of using (taking the sample from the question)
$date = strftime("%e %B %Y", strtotime('2010-01-08'))
convert that to:
$date = date('d M Y', strtotime('2010-01-08')

PHP date locale to dutch [duplicate]

I have a DateTime object which I'm currently formating via
$mytime->format("D d.m.Y")
Which gives me exactly the format I need:
Tue 5.3.2012
The only missing point is the correct language. I need German translation of Tue (Tuesday), which is Die (Dienstag).
This gives me the right locale setting
Locale::getDefault()
But I don't know how to tell DateTime::format to use it.
Isn't there a way to do something like:
$mytime->format("D d.m.Y", \Locale::getDefault());
You can use the Intl extension to format the date. It will format dates/times according to the chosen locale, or you can override that with IntlDateFormatter::setPattern().
A quicky example of using a custom pattern, for your desired output format, might look like.
$dt = new DateTime;
$formatter = new IntlDateFormatter('de_DE', IntlDateFormatter::SHORT, IntlDateFormatter::SHORT);
$formatter->setPattern('E d.M.yyyy');
echo $formatter->format($dt);
Which outputs the following (for today, at least).
Di. 4.6.2013
That's because format does not pay attention to locale. You should use strftime instead.
For example:
setlocale(LC_TIME, "de_DE"); //only necessary if the locale isn't already set
$formatted_time = strftime("%a %e.%l.%Y", $mytime->getTimestamp())
IntlDateFormatter is the way to go currently (2023).
<?php
$formatter = new IntlDateFormatter(
$locale, // the locale to use, e.g. 'en_GB'
$dateFormat, // how the date should be formatted, e.g. IntlDateFormatter::FULL
$timeFormat, // how the time should be formatted, e.g. IntlDateFormatter::FULL
'Europe/Berlin' // the time should be returned in which timezone?
);
echo $formatter->format(time());
Will give a different output, depending on what you pass as $locale and the date and time format. I wanted to add some samples for future reference. Note that IntlDateFormatter::GREGORIAN and IntlDateFormatter::LONG are interchangable.
Locale: en_US
Format for Date & Time: Results in:
IntlDateFormatter::FULL Friday, August 5, 2022 at 3:26:37 PM Central European Summer Time
IntlDateFormatter::LONG August 5, 2022 at 3:26:37 PM GMT+2
IntlDateFormatter::MEDIUM Aug 5, 2022, 3:26:37 PM
IntlDateFormatter::SHORT 8/5/22, 3:26 PM
Locale: en_GB
Format for Date & Time: Results in:
IntlDateFormatter::FULL Friday, 5 August 2022 at 15:26:37 Central European Summer Time
IntlDateFormatter::LONG 5 August 2022 at 15:26:37 CEST
IntlDateFormatter::MEDIUM 5 Aug 2022, 15:26:37
IntlDateFormatter::SHORT 05/08/2022, 15:26
Locale: de_DE
Format for Date & Time: Results in:
IntlDateFormatter::FULL Freitag, 5. August 2022 um 15:26:37 Mitteleuropäische Sommerzeit
IntlDateFormatter::LONG 5. August 2022 um 15:26:37 MESZ
IntlDateFormatter::MEDIUM 05.08.2022, 15:26:37
IntlDateFormatter::SHORT 05.08.22, 15:26
Locale: fr_FR
Format for Date & Time: Results in:
IntlDateFormatter::FULL vendredi 5 août 2022 à 15:26:37 heure d’été d’Europe centrale
IntlDateFormatter::LONG 5 août 2022 à 15:26:37 UTC+2
IntlDateFormatter::MEDIUM 5 août 2022 à 15:26:37
IntlDateFormatter::SHORT 05/08/2022 15:26
As salathe has already said, you can also use $formatter->setPattern to further customize the output if needed.
While setlocale() is the correct answer and will still work but is outdated now.
strftime has been DEPRECATED as of PHP 8.1.0 Relying on this function is highly discouraged.
And mentioned Intl extension works perfectly, but not always handy.
One of the simplest ways to work with dates and times is to use Carbon2, CakePHP Chronos or similar library. It provides a single interface to all date's manipulations, formatting, and calculations. If you work with dates a lot I recommend using Carbon and then doing something like this
$date = Carbon::now()->locale('fr_FR');
echo $date->isoFormat('dd DD.MM.YYYY');
Please note that the format differs from the date() one. Full list see in Carbon docs but mentioned D d.m.Y can be something like dd DD.MM.YYYY.
If your project accepts 3rd party libraries, it's really the way to go. Also, if you're using the framework, please check, maybe Carbon (or its wrapper) is already included.
I made something that just does that, because there doesn't seem to exist a simple solution anywhere online, except for with strftime, which is very much deprecated!
My solution extends DateTime::format() with international month and day names and doesn't require installing a bunch of modules, learning new date formatting ways, etc.
After including the classes provided below you can use it as follows. Instead of
$date = new DateTime("2010-01-01 1:23");
echo $date->format("l (D) Y-M-d (F)");
Result: Friday (Fri) 2010-Jan-01 (January)
You can now use
$date = new DateTimeIntl("2010-01-01 1:23");
echo $date->format("l (D) Y-M-d (F)");
Result: vrijdag (vr) 2010-jan.-01 (januari) (Dutch locale).
You can dynamically change the $datetime->locale if wanted.
$date = new DateTimeIntl("2010-01-01 1:23");
$date->locale = "it_IT" ;
echo $date->format("l (D) Y-M-d (F)");
Result: venerdì (ven) 2010-gen-01 (gennaio)
Include this:
class DateTimePatternReplace {
function __construct(public string $DateTimeCode,
public string $IntDateFormatterCode,
public string $tempDateTimePlaceHolder) {}
}
trait addIntlDate {
public string $locale="nl_NL" ; // REPLACE BY YOUR FAVORITE LOCALE
private function getIntResult(string $pattern) {
if ( ! isset($this->formatter) || $this->formatter->getLocale(Locale::VALID_LOCALE) != $this->locale ) {
$this->formatter = new IntlDateFormatter($this->locale);
$this->locale = $this->formatter->getLocale(Locale::VALID_LOCALE); // store the valid version of the locale
}
this->formatter->setPattern($pattern);
return $this->formatter->format($this);
}
function format(string $pattern): string {
// The third parameter can NOT contain normal latin letters, these are random,
// distinctive codes not likely to be in a date format string
$replacePatterns = [/*weekdays*/new DateTimePatternReplace('l', 'EEEE', '[*ł*]'),
new DateTimePatternReplace('D', 'EEE', '[*Đ*]'),
/*month*/ new DateTimePatternReplace('F', 'MMMM', '[*ƒ*]'),
new DateTimePatternReplace('M', 'MMM', '[*μ*]'),
// add new replacements here if needed
] ;
$codesFound=[] ;
foreach($replacePatterns as $p) {
if ( str_contains($pattern, $p->DateTimeCode)) {
// replace codes not prepended by a backslash.
// known bug: codes prepended by double backslashes will not be translated. Whatever.
$pattern = preg_replace('/(?<!\\\)'.preg_quote($p->DateTimeCode)."/", $p->tempDateTimePlaceHolder, $pattern);
$codesFound[] = $p ;
}
}
$result = parent::format($pattern) ;
foreach($codesFound as $p) {
$code = $this->getIntResult($p->IntDateFormatterCode);
$result = str_replace($p->tempDateTimePlaceHolder, $code, $result);
}
return $result ;
}
}
// you can remove this str_contains addition in PHP 8 or higher
if (!function_exists('str_contains')) {
function str_contains($haystack, $needle) {
return $needle !== '' && mb_strpos($haystack, $needle) !== false;
}
}
// end str_contains addition
class DateTimeIntl extends DateTime {
use addIntlDate;
}
class DateTimeImmutableIntl extends DateTimeImmutable {
use addIntlDate;
}
This code extends DateTime and DateTimeImmutable, extends their normal formatting with a locale. So this keeps everything extremely simple
You can add new patterns to be translated if needed by adding codes to the array: a formatting pattern in DateTime::format()-syntax, a corresponding formatting pattern in IntlDateFormatter::format-syntax, plus a placeholder to be used in DateTime::format that does NOT contains letters/codes/patterns that will be used/replaced by the DateTime::format method. See as example the current four codes that use no letters in ASCII lower than 128 letters. (They do use Polish, Greek, Dutch and Slovak letters just for fun.)
Built and tested in PHP 8.1.
For some older version of PHP you will have to change the first class to
class DateTimePatternReplace {
public string $DateTimeCode;
public string $IntDateFormatterCode;
public string $tempDateTimePlaceHolder;
function __construct(string $DateTimeCode, string $IntDateFormatterCode, string $tempDateTimePlaceHolder) {
$this->DateTimeCode = $DateTimeCode;
$this->IntDateFormatterCode = $IntDateFormatterCode;
$this->tempDateTimePlaceHolder = $tempDateTimePlaceHolder;
}
}
This is how I solved combining the features of DateTime and strftime().
The first allows us to manage strings with a weird date format, for example "Ymd" (stored in db from a datepicker).
The second allows us to translate a date string in some language.
For example we start from a value "20201129", and we want end with an italian readable date, with the name of day and month, also the first letter uppercase: "Domenica 29 novembre 2020".
// for example we start from a variable like this
$yyyymmdd = '20201129';
// set the local time to italian
date_default_timezone_set('Europe/Rome');
setlocale(LC_ALL, 'it_IT.utf8');
// convert the variable $yyyymmdd to a real date with DateTime
$truedate = DateTime::createFromFormat('Ymd', $yyyymmdd);
// check if the result is a date (true) else do nothing
if($truedate){
// output the date using strftime
// note the value passed using format->('U'), it is a conversion to timestamp
echo ucfirst(strftime('%A %d %B %Y', $truedate->format('U')));
}
// final result: Domenica 29 novembre 2020

Convert dutch time string to timestamp php

I have a function that reads out the date in a file on the first line. This date is formatted in dutch like this 2 mei 2013 or 28 jun. 2013
It needs to convert the date string into a timestamp, but whatever i try it won't work for the mei moths or any other dutch named month. Here is the code I currently have (the original function is a bit more code, but this is where it goes wrong)
function getTimestamp($date){
date_default_timezone_set('Europe/Amsterdam');
setlocale(LC_ALL, 'nl_NL');
$timestamp = strtotime($date);
return $timestamp;
}
Now, here are some results when using this function:
$timestamp = getTimestamp('28 jun. 2013') //1372370400
$timestamp2 = getTimestamp('2 mei 2013') // false
but, when i put this code in the function
echo strftime('%e %b %Y', 1367445600)."\n";
it prints '2 mei 2013'
How can I tell php not only format the date-time string in Dutch, but also read it in Dutch?
=======================
Thanks to some explanation below I now have the code working (this is the full function)
public function getReportDate(){
$mothsTranslated = array('mrt'=> 'mar','mei'=>'may', 'okt'=>'oct');
$content = file($this->file);
$line = $content[0];
$header = str_getcsv($line, $this->delimiter);
$date = str_replace('.', '', $header[1]);
foreach ($mothsTranslated as $dutch => $eng) {
if(strpos($date, $dutch) !== false){
$date = str_replace($dutch, $eng, $date);
}
}
$timestamp = strtotime($date);
return $timestamp;
}
Without creating your own date parser, the native PHP functions only use English dates.
However, there is an international dateformatter extension available for PHP. You can install this plugin and then would be able to parse non-english dates.
http://www.php.net/manual/en/intldateformatter.parse.php
As others found out, strtotime does not respect the set locale.
Indeed, it's description in the manual states: "Parse about any English textual datetime description into a Unix timestamp"
Solutions
You can use strptime() since PHP5 that does respect the locale (like strftime), but there are some warnings about using it on the php website.
You could write a function that replaces the Dutch month names to English month names and then calls strtotime.

Formatting DateTime object, respecting Locale::getDefault()

I have a DateTime object which I'm currently formating via
$mytime->format("D d.m.Y")
Which gives me exactly the format I need:
Tue 5.3.2012
The only missing point is the correct language. I need German translation of Tue (Tuesday), which is Die (Dienstag).
This gives me the right locale setting
Locale::getDefault()
But I don't know how to tell DateTime::format to use it.
Isn't there a way to do something like:
$mytime->format("D d.m.Y", \Locale::getDefault());
You can use the Intl extension to format the date. It will format dates/times according to the chosen locale, or you can override that with IntlDateFormatter::setPattern().
A quicky example of using a custom pattern, for your desired output format, might look like.
$dt = new DateTime;
$formatter = new IntlDateFormatter('de_DE', IntlDateFormatter::SHORT, IntlDateFormatter::SHORT);
$formatter->setPattern('E d.M.yyyy');
echo $formatter->format($dt);
Which outputs the following (for today, at least).
Di. 4.6.2013
That's because format does not pay attention to locale. You should use strftime instead.
For example:
setlocale(LC_TIME, "de_DE"); //only necessary if the locale isn't already set
$formatted_time = strftime("%a %e.%l.%Y", $mytime->getTimestamp())
IntlDateFormatter is the way to go currently (2023).
<?php
$formatter = new IntlDateFormatter(
$locale, // the locale to use, e.g. 'en_GB'
$dateFormat, // how the date should be formatted, e.g. IntlDateFormatter::FULL
$timeFormat, // how the time should be formatted, e.g. IntlDateFormatter::FULL
'Europe/Berlin' // the time should be returned in which timezone?
);
echo $formatter->format(time());
Will give a different output, depending on what you pass as $locale and the date and time format. I wanted to add some samples for future reference. Note that IntlDateFormatter::GREGORIAN and IntlDateFormatter::LONG are interchangable.
Locale: en_US
Format for Date & Time: Results in:
IntlDateFormatter::FULL Friday, August 5, 2022 at 3:26:37 PM Central European Summer Time
IntlDateFormatter::LONG August 5, 2022 at 3:26:37 PM GMT+2
IntlDateFormatter::MEDIUM Aug 5, 2022, 3:26:37 PM
IntlDateFormatter::SHORT 8/5/22, 3:26 PM
Locale: en_GB
Format for Date & Time: Results in:
IntlDateFormatter::FULL Friday, 5 August 2022 at 15:26:37 Central European Summer Time
IntlDateFormatter::LONG 5 August 2022 at 15:26:37 CEST
IntlDateFormatter::MEDIUM 5 Aug 2022, 15:26:37
IntlDateFormatter::SHORT 05/08/2022, 15:26
Locale: de_DE
Format for Date & Time: Results in:
IntlDateFormatter::FULL Freitag, 5. August 2022 um 15:26:37 Mitteleuropäische Sommerzeit
IntlDateFormatter::LONG 5. August 2022 um 15:26:37 MESZ
IntlDateFormatter::MEDIUM 05.08.2022, 15:26:37
IntlDateFormatter::SHORT 05.08.22, 15:26
Locale: fr_FR
Format for Date & Time: Results in:
IntlDateFormatter::FULL vendredi 5 août 2022 à 15:26:37 heure d’été d’Europe centrale
IntlDateFormatter::LONG 5 août 2022 à 15:26:37 UTC+2
IntlDateFormatter::MEDIUM 5 août 2022 à 15:26:37
IntlDateFormatter::SHORT 05/08/2022 15:26
As salathe has already said, you can also use $formatter->setPattern to further customize the output if needed.
While setlocale() is the correct answer and will still work but is outdated now.
strftime has been DEPRECATED as of PHP 8.1.0 Relying on this function is highly discouraged.
And mentioned Intl extension works perfectly, but not always handy.
One of the simplest ways to work with dates and times is to use Carbon2, CakePHP Chronos or similar library. It provides a single interface to all date's manipulations, formatting, and calculations. If you work with dates a lot I recommend using Carbon and then doing something like this
$date = Carbon::now()->locale('fr_FR');
echo $date->isoFormat('dd DD.MM.YYYY');
Please note that the format differs from the date() one. Full list see in Carbon docs but mentioned D d.m.Y can be something like dd DD.MM.YYYY.
If your project accepts 3rd party libraries, it's really the way to go. Also, if you're using the framework, please check, maybe Carbon (or its wrapper) is already included.
I made something that just does that, because there doesn't seem to exist a simple solution anywhere online, except for with strftime, which is very much deprecated!
My solution extends DateTime::format() with international month and day names and doesn't require installing a bunch of modules, learning new date formatting ways, etc.
After including the classes provided below you can use it as follows. Instead of
$date = new DateTime("2010-01-01 1:23");
echo $date->format("l (D) Y-M-d (F)");
Result: Friday (Fri) 2010-Jan-01 (January)
You can now use
$date = new DateTimeIntl("2010-01-01 1:23");
echo $date->format("l (D) Y-M-d (F)");
Result: vrijdag (vr) 2010-jan.-01 (januari) (Dutch locale).
You can dynamically change the $datetime->locale if wanted.
$date = new DateTimeIntl("2010-01-01 1:23");
$date->locale = "it_IT" ;
echo $date->format("l (D) Y-M-d (F)");
Result: venerdì (ven) 2010-gen-01 (gennaio)
Include this:
class DateTimePatternReplace {
function __construct(public string $DateTimeCode,
public string $IntDateFormatterCode,
public string $tempDateTimePlaceHolder) {}
}
trait addIntlDate {
public string $locale="nl_NL" ; // REPLACE BY YOUR FAVORITE LOCALE
private function getIntResult(string $pattern) {
if ( ! isset($this->formatter) || $this->formatter->getLocale(Locale::VALID_LOCALE) != $this->locale ) {
$this->formatter = new IntlDateFormatter($this->locale);
$this->locale = $this->formatter->getLocale(Locale::VALID_LOCALE); // store the valid version of the locale
}
this->formatter->setPattern($pattern);
return $this->formatter->format($this);
}
function format(string $pattern): string {
// The third parameter can NOT contain normal latin letters, these are random,
// distinctive codes not likely to be in a date format string
$replacePatterns = [/*weekdays*/new DateTimePatternReplace('l', 'EEEE', '[*ł*]'),
new DateTimePatternReplace('D', 'EEE', '[*Đ*]'),
/*month*/ new DateTimePatternReplace('F', 'MMMM', '[*ƒ*]'),
new DateTimePatternReplace('M', 'MMM', '[*μ*]'),
// add new replacements here if needed
] ;
$codesFound=[] ;
foreach($replacePatterns as $p) {
if ( str_contains($pattern, $p->DateTimeCode)) {
// replace codes not prepended by a backslash.
// known bug: codes prepended by double backslashes will not be translated. Whatever.
$pattern = preg_replace('/(?<!\\\)'.preg_quote($p->DateTimeCode)."/", $p->tempDateTimePlaceHolder, $pattern);
$codesFound[] = $p ;
}
}
$result = parent::format($pattern) ;
foreach($codesFound as $p) {
$code = $this->getIntResult($p->IntDateFormatterCode);
$result = str_replace($p->tempDateTimePlaceHolder, $code, $result);
}
return $result ;
}
}
// you can remove this str_contains addition in PHP 8 or higher
if (!function_exists('str_contains')) {
function str_contains($haystack, $needle) {
return $needle !== '' && mb_strpos($haystack, $needle) !== false;
}
}
// end str_contains addition
class DateTimeIntl extends DateTime {
use addIntlDate;
}
class DateTimeImmutableIntl extends DateTimeImmutable {
use addIntlDate;
}
This code extends DateTime and DateTimeImmutable, extends their normal formatting with a locale. So this keeps everything extremely simple
You can add new patterns to be translated if needed by adding codes to the array: a formatting pattern in DateTime::format()-syntax, a corresponding formatting pattern in IntlDateFormatter::format-syntax, plus a placeholder to be used in DateTime::format that does NOT contains letters/codes/patterns that will be used/replaced by the DateTime::format method. See as example the current four codes that use no letters in ASCII lower than 128 letters. (They do use Polish, Greek, Dutch and Slovak letters just for fun.)
Built and tested in PHP 8.1.
For some older version of PHP you will have to change the first class to
class DateTimePatternReplace {
public string $DateTimeCode;
public string $IntDateFormatterCode;
public string $tempDateTimePlaceHolder;
function __construct(string $DateTimeCode, string $IntDateFormatterCode, string $tempDateTimePlaceHolder) {
$this->DateTimeCode = $DateTimeCode;
$this->IntDateFormatterCode = $IntDateFormatterCode;
$this->tempDateTimePlaceHolder = $tempDateTimePlaceHolder;
}
}
This is how I solved combining the features of DateTime and strftime().
The first allows us to manage strings with a weird date format, for example "Ymd" (stored in db from a datepicker).
The second allows us to translate a date string in some language.
For example we start from a value "20201129", and we want end with an italian readable date, with the name of day and month, also the first letter uppercase: "Domenica 29 novembre 2020".
// for example we start from a variable like this
$yyyymmdd = '20201129';
// set the local time to italian
date_default_timezone_set('Europe/Rome');
setlocale(LC_ALL, 'it_IT.utf8');
// convert the variable $yyyymmdd to a real date with DateTime
$truedate = DateTime::createFromFormat('Ymd', $yyyymmdd);
// check if the result is a date (true) else do nothing
if($truedate){
// output the date using strftime
// note the value passed using format->('U'), it is a conversion to timestamp
echo ucfirst(strftime('%A %d %B %Y', $truedate->format('U')));
}
// final result: Domenica 29 novembre 2020

strtotime With Different Languages?

Does strtotime only work in the default language on the server? The below code should resolve to august 11, 2005, however it uses the french "aout" instead of the english "aug".
Any ideas how to handle this?
<?php
$date = strtotime('11 aout 05');
echo date('d M Y',$date);
?>
As mentioned strtotime does not take locale into account. However you could use strptime (see http://ca1.php.net/manual/en/function.strptime.php), since according to the docs:
Month and weekday names and other language dependent strings respect the current locale set with setlocale() (LC_TIME).
Note that depending on your system, locale and encoding you will have to account for accented characters.
French month dates are:
janvier février mars avril mai juin juillet août septembre octobre
novembre décembre
Hence, for the very specific case where months are in French you could use
function myStrtotime($date_string) { return strtotime(strtr(strtolower($date_string), array('janvier'=>'jan','février'=>'feb','mars'=>'march','avril'=>'apr','mai'=>'may','juin'=>'jun','juillet'=>'jul','août'=>'aug','septembre'=>'sep','octobre'=>'oct','novembre'=>'nov','décembre'=>'dec'))); }
The function anyway does not break if you pass $date_string in English, because it won't do any substitution.
From the docs
Parse about any English textual datetime description into a Unix
timestamp
Edit: Six years down the road now, and what was meant to be a side-note about why strtotime() was an inappropriate solution for the issue at hand became the accepted answer 😲
To better answer the actual question I want to echo Marc B's answer: despite the downvotes, date_create_from_format, paired with a custom Month interpreter will provide the most reliable solution
However it appears that there is still no silver-bullet for international date parsing built-in to PHP for the time being.
This method should work for you using strftime:
setlocale (LC_TIME, "fr_FR.utf8"); //Setting the locale to French with UTF-8
echo strftime(" %d %h %Y",strtotime($date));
strftime
I wrote a simple function partially solves this problem.
It does not work as a full strtotme(), but it determines the number of months names in the dates.
<?php
// For example, I get the name of the month from a
// date "1 January 2015" and set him (with different languages):
echo month_to_number('January').PHP_EOL; // returns "01" (January)
echo month_to_number('Января', 'ru_RU').PHP_EOL; // returns "01" (January)
echo month_to_number('Мая', 'ru_RU').PHP_EOL; // returns "05" (May)
echo month_to_number('Gennaio', 'it_IT').PHP_EOL; // returns "01" (January)
echo month_to_number('janvier', 'fr_FR').PHP_EOL; // returns "01" (January)
echo month_to_number('Août', 'fr_FR').PHP_EOL; // returns "08" (August)
echo month_to_number('Décembre', 'fr_FR').PHP_EOL; // returns "12" (December)
Similarly, we can proceed to determine the numbers and days of the week, etc.
Function:
<?php
function month_to_number($month, $locale_set = 'ru_RU')
{
$month = mb_convert_case($month, MB_CASE_LOWER, 'UTF-8');
$month = preg_replace('/я$/', 'й', $month); // fix for 'ru_RU'
$locale =
setlocale(LC_TIME, '0');
setlocale(LC_TIME, $locale_set.'.UTF-8');
$month_number = FALSE;
for ($i = 1; $i <= 12; $i++)
{
$time_month = mktime(0, 0, 0, $i, 1, 1970);
$short_month = date('M', $time_month);
$short_month_lc = strftime('%b', $time_month);
if (stripos($month, $short_month) === 0 OR
stripos($month, $short_month_lc) === 0)
{
$month_number = sprintf("%02d", $i);
break;
}
}
setlocale(LC_TIME, $locale); // return locale back
return $month_number;
}
The key to solving this question is to convert foreign textual representations to their English counterparts. I also needed this, so inspired by the answers already given I wrote a nice and clean function which would work for retrieving the English month name.
function getEnglishMonthName($foreignMonthName,$setlocale='nl_NL'){
setlocale(LC_ALL, 'en_US');
$month_numbers = range(1,12);
foreach($month_numbers as $month)
$english_months[] = strftime('%B',mktime(0,0,0,$month,1,2011));
setlocale(LC_ALL, $setlocale);
foreach($month_numbers as $month)
$foreign_months[] = strftime('%B',mktime(0,0,0,$month,1,2011));
return str_replace($foreign_months, $english_months, $foreignMonthName);
}
echo getEnglishMonthName('juli');
// Outputs July
You can adjust this for days of the week aswell and for any other locale.
Adding this as an extended version of Marco Demaio answer. Added french days of the week and months abbreviations:
<?php
public function frenchStrtotime($date_string) {
$date_string = str_replace('.', '', $date_string); // to remove dots in short names of months, such as in 'janv.', 'févr.', 'avr.', ...
return strtotime(
strtr(
strtolower($date_string), [
'janvier'=>'jan',
'février'=>'feb',
'mars'=>'march',
'avril'=>'apr',
'mai'=>'may',
'juin'=>'jun',
'juillet'=>'jul',
'août'=>'aug',
'septembre'=>'sep',
'octobre'=>'oct',
'novembre'=>'nov',
'décembre'=>'dec',
'janv'=>'jan',
'févr'=>'feb',
'avr'=>'apr',
'juil'=>'jul',
'sept'=>'sep',
'déc'=>'dec',
'lundi' => 'monday',
'mardi' => 'tuesday',
'mercredi' => 'wednesday',
'jeudi' => 'thursday',
'vendredi' => 'friday',
'samedi' => 'saturday',
'dimanche' => 'sunday',
]
)
);
}
It's locale dependent. If it had to check every language for every parse, it'd take nigh-on FOREVER to parse even the simplest of date strings.
If you've got a string with known format, consider using date_create_from_format(), which'll be far more efficient and less error-print
Try to set the locale before conversion:
setlocale(LC_TIME, "fr_FR");

Categories