I would like to convert a String date to an Object date.
String date :
jeu. 26 avril 2018 10:25
to this object date
{ ["date"]=> string(26) "2018-04-26 10:34:50.000000" ["timezone_type"]=> int(3) ["timezone"]=> string(12) "Africa/Tunis" }
so far i've tried :
Carbon::createFromFormat("Y-m-d H:i:s", 'jeu. 26 avril 2018 10:25')
i've got an exception :
Unexpected data found. Unexpected data found. The separation symbol
could not be found Data missing
u have to change the format:
Carbon::createFromFormat("D. d M Y H:i", 'jeu. 26 avril 2018 10:25')
Note: i assume jeu is day name.
You need to set locale and proper wildcard characters to read proper date format
You can find placeholder here when working with locale : http://php.net/manual/en/function.strftime.php
this code should work
<?php
// use this only if you working on other locale want to restore OLD locale back
// ====================================
$oldLocale = setlocale(LC_ALL, 0);
var_dump(setlocale(LC_ALL, 'fr_FR'));
// ^ this must return 'fr_FR' then only we confirm locale is set
// if return FALSE then install 'fr_FR' locale for PHP on server
// ====================================
// day name will be having .(dot) at end according abbreviation
// lun., mar., mer., jeu., ven., sam., dim.
$timeChunks = strptime('jeu. 26 avril 2018 10:25', '%a %d %b %Y %H:%M');
// ====================================
// use this only if you working on other locale want to restore OLD locale
setlocale(LC_ALL, $oldLocale);
// ====================================
$date = Carbon::create(
($timeChunks['tm_year'] + 1900) , // year
($timeChunks['tm_mon'] + 1), // month
$timeChunks['tm_mday'], // day
$timeChunks['tm_hour'], // hour
$timeChunks['tm_min'], // min
$timeChunks['tm_sec'] // second
);
// tm_year starts from 1900 so we need to add it
// tm_mon is 0 to 11 so add 1
var_dump($date);
if any doubts then please comment
Related
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
I have a problem to return date in french in my laravel project,
in my model I have the following method :
public function getShowDateAttribute()
{
Carbon::setLocale('fr_FR');
return Carbon::parse($this->conference_date)->format('D d F Y');
}
But the date is still in english,
I've tried also
setLocale(LC_TIME,'fr_FR');
But the date is still in english.
I've also tried to use the php date function and the localizedFormat method of Carbon but always same result : date in english,
would you have any idea of the problem ?
( I checked with locale -a and fr_FR is available on my computer )
Thank you
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
So, here is the new recommended way to handle internationalization with Carbon.
$date = Carbon::now()->locale('fr_FR');
echo $date->locale(); // fr_FR
echo $date->diffForHumans(); // il y a quelques secondes
echo $date->monthName; // décembre
echo $date->isoFormat('LLLL'); // undi 10 décembre 2018 16:20
For more help go here
Just use fr only while setting locale. Other looks fine
Carbon::setLocale('fr');
I wan't to get a PHP date() from specified weekday in a given week.
For example:
Weekday: Thursday - in week:8 - year:13 (means 2013).
I would like to return a date from these specified values. The phpdate will in this case return: "21 Feb 2013", which is a Thursday in week 8 of 2013.
Please fill in this php-method:
function getDateWithSpecifiedValues($weekDayStr,$week,$year) {
//return date();
}
Where the example:
getDateWithSpecifiedValues("Tuesday",8,13);
will return a phpdate of "19 Feb 2013"
First, you have to define what you mean by "week of the year". There are several different definitions. Does the first week start on Jan 1? On the first Sunday or Monday? Is it number 1 or 0?
There is a standard definition, codified in ISO 8601, which says that weeks run from Monday through Sunday, the first one of the year is the one with at least 4 days of the new year in it, and that week is number 1. Your example expected output is consistent with that definition.
So you can convert the values by putting them into a string and passing that string to strptime, along with a custom format string telling it what the fields in the string are. For example, the the week number itself should be indicated in the format string by %V.
For the weekday, the format depends on how you want to provide it as input to your function. If you have the full name (e.g. "Thursday"), that's %A. If you have the abbreviated name (e.g. "Thu"), that's %a. If you have a number (e.g. 4), that's either %w (if Sundays are 0) or %u (if Sundays are 7). (If you're not sure, you can always just use %w and pass the number % 7.)
Now, the year should be %G (full year) or %g (just the last two digits). It's different from the normal calendar year fields (%Y for 2014 and %y for 13) because, for example, week 1 of 2014 actually started on December 30, 2013, which obviously has a '%Y' of 2013 where we want 2014. However, the G fields don't work properly with strptime, so you'll have to use the Y's.
For example:
$date_array = strptime("$weekDayStr $week $year", '%A %V %y');
That's a good start, but the return value of strptime is an array:
array('tm_sec' => seconds, 'tm_min' => minutes, tm_hour => hour,
tm_mday => day of month, tm_mon => month number (0..11), tm_year => year - 1900)
And that array is not the input expected by any of the other common date or time functions, as far as I can tell. You have to pull the values out yourself and modify them in some cases and pass the result to something to get what you want. For instance:
$time_t = mktime($date_array['tm_hour'], $date_array['tm_min'],
$date_array['tm_sec'], $date_array['tm_mon']+1,
$date_array['tm_mday'], $date_array['tm_year']+1900);
And then you can return that in whatever form you need. Here I'm returning it as a string:
function getDateWithSpecifiedValues($weekDayStr,$week,$year) {
$date_array = strptime("$weekDayStr $week $year", '%A %V %y');
$time_t = mktime($date_array['tm_hour'], $date_array['tm_min'],
$date_array['tm_sec'], $date_array['tm_mon']+1,
$date_array['tm_mday'], $date_array['tm_year']+1900);
return strftime('%d %b %Y', $time_t);
}
For example,
php > print(getDateWithSpecifiedValues('Thursday',8,13)."\n");
21 Feb 2013
Try this function:
function getDateWithSpecifiedValues($weekDayStr, $week, $year) {
$dt = DateTime::createFromFormat('y, l', "$year, $weekDayStr");
return $dt->setISODate($dt->format('o'), $week, $dt->format('N'))->format('j M Y');
}
demo
I'm fairly certain neither 21st of January or the 19th of January is in week 8.
You can however use strptime to parse custom formats:
var_dump(strptime("Thursday 8 13", "%A %V %y"));
array(9) {
["tm_sec"]=>
int(0)
["tm_min"]=>
int(0)
["tm_hour"]=>
int(0)
["tm_mday"]=>
int(21)
["tm_mon"]=>
int(1)
["tm_year"]=>
int(113)
["tm_wday"]=>
int(4)
["tm_yday"]=>
int(58)
["unparsed"]=>
string(0) ""
}
See the documentation for strptime for the meaning of each value in the returned array.
Good !
I am having some difficulties with extracting data from a date. The thing is that I get a number from an undocumented API.
"created": 734394
"last_chapter_date": 734883
I tried dividing it by 365,242 days (exact amount of days a year)
2010,705231052289
So apparently these are the number of days passed since 0.0.0000
I am currently trying something like that:
http://jsfiddle.net/LRUy5/4/
function zero21970(nDays) {
// 0 70 2013
// |-----|-----|
// 0 to date
var dateMils = nDays*24*60*60*100;
// 0 to 1970
zeroTo1970 = (1970*365.242)*24*60*60*100;
//subtract time from 0-1970 from the time 0-date
//to cut out the part from 1970-today
return new Date(dateMils-zeroTo1970);
}
//http://www.mangaeden.com/api/manga/4e70e9f6c092255ef7004344/
zero21970(734394) //-> Jan 26 1974
I need to save it in a database and work with it via php or javascript..
Does anyone recognize this kind of format or do you know a convenient way of formatting it?
Edit: I should add that the last chapter came out around 15.01.2013.. just to have something to grab.
Updated version:
I guess if the last chapter was from 2013, then the value is a number of days from 01.01.0001. So we can update the initial date as well as change setHours to setDate method for more accuracy:
var date = new Date("0001");
date.setDate(734883);
date.toGMTString(); // "Tue, 15 Jan 2013 00:00:00 GMT"
DEMO: http://jsfiddle.net/LRUy5/6/
Old version:
I found one solution that successfully works at my computer:
var date = new Date("0000");
date.setHours(734394 * 24);
date.toGMTString(); // "Mon, 13 Sep 2010 21:00:00 GMT"
DEMO: http://jsfiddle.net/LRUy5/5/
If you're using PHP, then you should replace
return new Date(dateMils-zeroTo1970);
with
return date('Y-m-d', (dateMils-zeroTo1970));
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