Related
Ive read several stackoverflows about set locale. I tested locale -a in the terminal to see if my locale was in there, and it was. The following rule of code is added in the appServiceProvider:
public function boot()
{
Carbon::setLocale($this->app->getLocale());
}
The $this->app->getLocale() returns "nl"
Anyone know why Carbon still shows Sunday instead of Zondag for example?
Translating a carbon date using global localized format
Tested in: Laravel 5.8, Laravel 6, Laravel 8
In config/app.php
'locale' => 'id', // The default is 'en', but this time I want localize them to Indonesian (ID)
Then, to make locale output do something like this:
// WITHOUT LOCALE
Carbon\Carbon::parse('2019-03-01')->format('d F Y'); //Output: "01 March 2019"
now()->subMinute(5)->diffForHumans(); // Output: "5 minutes ago"
// WITH LOCALE
Carbon\Carbon::parse('2019-03-01')->translatedFormat('d F Y'); // Output: "01 Maret 2019"
now()->subMinute(5)->diffForHumans(); // Output: "5 menit yang lalu"
For more information about converting localize dates you can see on below link
https://carbon.nesbot.com/docs/#api-localization
You might want to use setLocale(LC_TIME, $this->app->getLocale()) somewhere at the start of your application.
Then if you wish to have the localized date format with local names use the formatLocalized function
Carbon::now()->formatLocalized('%d %B %Y');
See http://php.net/manual/en/function.strftime.php for parameter for formatting
Researching I have found two alternative options:
$date = Carbon::now();
$date->locale('de')->translatedFormat('d F Y');
and:
$date = Carbon::now();
$carbonDateFactory = new CarbonFactory([
'locale' => 'de_DE',
'timezone' => 'Europe/Paris',
]);
$carbonDateFactory->make($date)->isoFormat('d MMMM YYYY');
and the ISO compatible format symbols are here
I solved this by calling setLocale on multiple classes:
$locale = 'nl_NL';
\Carbon\Carbon::setLocale($locale);
\Carbon\CarbonImmutable::setLocale($locale);
\Carbon\CarbonPeriod::setLocale($locale);
\Carbon\CarbonInterval::setLocale($locale);
\Illuminate\Support\Carbon::setLocale($locale);
There's also this ServiceProvider that does the same.
In your AppServiceProvider's register function:
setlocale(LC_TIME, 'nl_NL.utf8');
Carbon::setLocale(config('app.locale'));
Then use translatedFormat() instead of format() or formatLocalized() which is deprecated.
This uses the date() patern which works like format() but translates the string using the current locale.
read more here and here.
try this : setLocale(LC_TIME, app()->getLocale());
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
Is there a way in PHP to get a string from a DateTime object considering the date format according to the locale configuration without having an array of countries => formats ?
$dt = DateTime::createFromFormat(DateTime::ISO8601, '2016-07-27T19:30:00Z');
$ $usadt = /* What PHP function here? */
$ $brazildt = /* What PHP function here? */
echo ("USA Format: " . $usadt);
echo ("Brazil Format: " . $brazildt);
USA Format: 2016/07/27 07:30pm
Brazil Format: 27/07/2016 19:30
In the strftime() php manual it says
Format the time and/or date according to locale settings. Month and weekday names and other language-dependent strings respect the current locale set with setlocale().
So take a look at setlocale() and change it before using formatted date.
how to format for your datetime locale
%x Preferred date representation based on locale, without the time
%X Preferred time representation based on locale, without the date
example
$dt = DateTime::createFromFormat(DateTime::ISO8601, '2016-07-27T19:30:00Z');
setlocale(LC_TIME, 'en_US');
$usadt = strftime('%x %X', $dt->getTimestamp());
setlocale(LC_TIME, 'pt_BR.UTF-8');
$brazildt = strftime('%x %X', $dt->getTimestamp());
echo "USA Format: $usadt<br>";
echo "Brazil Format: $brazildt<br>";
outputs
USA Format: 07/27/2016 12:30:00 PM
Brazil Format: 27-07-2016 12:30:00
note
I got the locales from this page;
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.
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