intl
, which is included in the kernel from version 5.3. And in this intl
there is a class IntlDateFormatter
, which in turn has several predefined formats. We use it LONG
format. <?php foreach (['en_US', 'ru_RU', 'es_ES', 'fa_IR'] as $locale) { $formatter = new IntlDateFormatter( $locale, IntlDateFormatter::LONG, IntlDateFormatter::NONE, 'Europe/Moscow' ); echo $formatter->format(1455111783), PHP_EOL; }
February 10, 2016 10 2016 . 10 de febrero de 2016 ۱۰ ﻑﻭﺭیﻩٔ ۲۰۱۶ ﻡ. // - RTL-,
February 10 10 10 de febrero ۱۰ ﻑﻭﺭیﻩٔ ﻡ. // , , ,
LONG
, but without a year, right?IntlDateFormatter
only four standard formats: FULL
, LONG
, MEDIUM
and SHORT
, and each of them has a year. <?php $formats = [ IntlDateFormatter::FULL, IntlDateFormatter::LONG, IntlDateFormatter::MEDIUM, IntlDateFormatter::SHORT, ]; foreach ($formats as $format) { $formatter = new IntlDateFormatter( 'en_US', $format, IntlDateFormatter::NONE, 'Europe/Moscow' ); echo $formatter->format(1455111783), PHP_EOL; }
Wednesday, February 10, 2016 February 10, 2016 Feb 10, 2016 2/10/16
LONG
, right? Ready to argue that way. Without examples it can be difficult to understand what the problem is. Let's just see. February 10, 2016 10 2016 . 10 de febrero de 2016 ۱۰ ﻑﻭﺭیﻩٔ ۲۰۱۶ ﻡ.
February 10, 10 . 10 de febrero de ۱۰ ﻑﻭﺭیﻩٔ ﻡ.
,
and the .
and the de
and definitely something else in the last line, which I cannot single out?IntlDateFormatter
actually works only with patterns inside (format constants are simply converted to the corresponding pattern), and when creating you can specify your own. <?php foreach (['en_US', 'ru_RU', 'es_ES', 'fa_IR'] as $locale) { $formatter = new IntlDateFormatter( $locale, IntlDateFormatter::NONE, IntlDateFormatter::NONE, 'Europe/Moscow', null, "d MMMM" ); echo $formatter->format(1455111783), PHP_EOL; }
10 February 10 10 febrero ۱۰ فوریهٔ
February 10 10 10 de febrero ۱۰ ﻑﻭﺭیﻩٔ ﻡ.
<?php foreach (['en_US', 'ru_RU', 'es_ES', 'fa_IR'] as $locale) { $formatter = new IntlDateFormatter( $locale, IntlDateFormatter::LONG, IntlDateFormatter::NONE, 'Europe/Moscow' ); echo $formatter->getPattern(), PHP_EOL; }
MMMM d, y d MMMM y ''. d 'de' MMMM 'de' y d MMMM y G
intl
- the DateTimePatternGenerator
class from ICU. It is made exactly in order to solve our little puzzle and all other similar.ICU is a mature, widely used set of C / C ++ and Java library software providing unicode and globalization support for software applications. CU C ++ and Java software is widely portable and gives
Formatting: Format numbers, dates, times and amounts according to the conventions of a chosen locale. This code includes the correct language, choosing the appropriate abbreviations, ordering fields correctly, etc. This data also comes from the Common Locale Data Repository.
intl
extension itself is not capable of any magic, it is something like a proxy to these libraries. $ php -i | grep intl -A5 intl Internationalization support => enabled version => 1.1.0 ICU version => 56.1 ICU Data version => 56.1
IntlDateFormatter
, ICU must be installed on your system (or you must build PHP with ICU initially). Different versions of ICU will give different formatting results. $ dpkg -S icu libicu52:amd64: /usr/lib/x86_64-linux-gnu/libicule.so.52.1 libicu52:amd64: /usr/lib/x86_64-linux-gnu/libicule.so.52 libicu52:amd64: /usr/lib/x86_64-linux-gnu/libicutest.so.52 ...
DateTimePatternGenerator
, tellDateTimePatternGenerator
, this is, in my opinion, the most magical thing in ICU of those that are about formatting date-time.This class provides you with a "yy-mm-dd" format.
By adding successive patterns. Once it is done, it can be made using a skeleton, The generator will return the "best fit" pattern to that skeleton.
This is a method that has been used to get the best way to get it. However, generators can be built directly from other data as well.
getBestPattern
method, and it returns the most appropriate pattern, and with it we already know what to do: transfer to IntlDateFormatter
- and that's it! $skeleton = "MMMMd"; foreach (['en_US', 'ru_RU', 'es_ES', 'fa_IR'] as $locale) { $pgen = new IntlDateTimePatternGenerator($locale); $pattern = $pgen->getBestPattern($skeleton); $formatter = new IntlDateFormatter( $locale, IntlDateFormatter::NONE, IntlDateFormatter::NONE, 'Europe/Moscow', null, $pattern ); echo $formatter->format(1455111783), PHP_EOL; }
February 10 10 10 de febrero ۱۰ ﻑﻭﺭیﻩٔ ﻡ.
<?php // ... foreach ($locales as $locale) { $pattern = <<<CONFIG '%s' => [ 'medium_no_year' => "%s", // %s 'long_no_year' => "%s", // %s ], CONFIG; $mediumF = new IntlDateFormatter($locale, IntlDateFormatter::MEDIUM, IntlDateFormatter::NONE); $longF = new IntlDateFormatter($locale, IntlDateFormatter::LONG, IntlDateFormatter::NONE); printf( $pattern, $locale, $mediumF->getPattern(), $mediumF->format(1455111783), $longF->getPattern(), $longF->format(1455111783) ); }
'en_US' => [ 'medium_no_year' => "MMM d, y", // Feb 10, 2016 'long_no_year' => "MMMM d, y", // February 10, 2016 ], 'ru_RU' => [ 'medium_no_year' => "d MMM y ''.", // 10 . 2016 . 'long_no_year' => "d MMMM y ''.", // 10 2016 . ], 'es_ES' => [ 'medium_no_year' => "d MMM y", // 10 feb. 2016 'long_no_year' => "d 'de' MMMM 'de' y", // 10 de febrero de 2016 ], 'fa_IR' => [ 'medium_no_year' => "d MMM y G", // ۱۰ فوریهٔ ۲۰۱۶ م. 'long_no_year' => "d MMMM y G", // ۱۰ فوریهٔ ۲۰۱۶ م. ],
'en_US' => [ 'medium_no_year' => "MMM d", // Feb 10 'long_no_year' => "MMMM d", // February 10 ], 'ru_RU' => [ 'medium_no_year' => "d MMM", // 10 . 'long_no_year' => "d MMMM", // 10 ], 'es_ES' => [ 'medium_no_year' => "d MMM", // 10 feb. 'long_no_year' => "d 'de' MMMM", // 10 de febrero ], 'fa_IR' => [ 'medium_no_year' => "d MMM", // ۱۰ فوریهٔ م. 'long_no_year' => "d MMMM", // ۱۰ فوریهٔ م. ],
<?php foreach (['en_US', 'ru_RU', 'es_ES', 'fa_IR'] as $locale) { $pattern = <<<CONFIG '%s' => [ 'medium_no_year-short' => "%s", // %s 'long_no_year-short' => "%s", // %s ], CONFIG; $mediumF = new IntlDateFormatter($locale, IntlDateFormatter::MEDIUM, IntlDateFormatter::SHORT); $longF = new IntlDateFormatter($locale, IntlDateFormatter::LONG, IntlDateFormatter::SHORT); printf( $pattern, $locale, $mediumF->getPattern(), $mediumF->format(1455111783), $longF->getPattern(), $longF->format(1455111783) ); }
'en_US' => [ 'medium_no_year-short' => "MMM d, y, h:mm a", // Feb 10, 2016, 2:43 PM 'long_no_year-short' => "MMMM d, y 'at' h:mm a", // February 10, 2016 at 2:43 PM ], 'ru_RU' => [ 'medium_no_year-short' => "d MMM y ''., H:mm", // 10 . 2016 ., 14:43 'long_no_year-short' => "d MMMM y ''., H:mm", // 10 2016 ., 14:43 ], 'es_ES' => [ 'medium_no_year-short' => "d MMM y H:mm", // 10 feb. 2016 14:43 'long_no_year-short' => "d 'de' MMMM 'de' y, H:mm", // 10 de febrero de 2016, 14:43 ], 'fa_IR' => [ 'medium_no_year-short' => "d MMM y G، H:mm", // ۱۰ فوریهٔ ۲۰۱۶ م.، ۱۴:۴۳ 'long_no_year-short' => "d MMMM y G، ساعت H:mm", // ۱۰ فوریهٔ ۲۰۱۶ م.، ساعت ۱۴:۴۳ ],
'en_US' => [ 'medium_no_year-short' => "MMM d, h:mm a", // Feb 10, 2:43 PM 'long_no_year-short' => "MMMM d, 'at' h:mm a", // February 10, at 2:43 PM ], 'ru_RU' => [ 'medium_no_year-short' => "d MMM, H:mm", // 10 ., 14:43 'long_no_year-short' => "d MMMM, H:mm", // 10 , 14:43 ], 'es_ES' => [ 'medium_no_year-short' => "d MMM H:mm", // 10 feb. 14:43 'long_no_year-short' => "d 'de' MMMM, H:mm", // 10 de febrero, 14:43 ], 'fa_IR' => [ 'medium_no_year-short' => "d MMM، H:mm", // ۱۰ فوریهٔ، ۱۴:۴۳ 'long_no_year-short' => "d MMMM، ساعت H:mm", // ۱۰ فوریهٔ، ساعت ۱۴:۴۳ ],
I did not begin to look at frameworks, because I think that this is not a framework task. Although there may be some very basic support ... Well, maybe. Actually, I tried it, looked at Yii2, and they just recommend using pure intl
. So let's get a better CMS.
intl
key just for the localization pattern. And now they just do not care.intl
keys from this branch)functions.php
interest to us here is the date_i18n
from functions.php
(by the way, guys, wtf? A file with functions from 5.2k lines of code? Seriously? We’ve got the 2016th already.).date_format
. It seems that they are trying to localize the names of the months and days of the week, no more. Connoisseurs correct me if I am mistaken.date_format
uses date_format
(like many others) and does not use intl
. Is that justified? In my opinion, no. intl
since version 5.3 is included in the kernel, and we already have PHP 7 in the yard, and 5.5 is the minimum requirement for most modern code. That is, I absolutely understand when frameworks do not use any third-party extensions or chips of the latest versions of the language, because they believe that their code should work even on an iron, and they already have a lot of users who have code on irons of old versions. But this is clearly not the case. Call it "Legacy" or "technical debt" or something else and continue.strftime
sounds a little better than date_format
(there are formats that give a false sense of correct localization) or nothing when we talk about localization, but this function does not do what we need.IntlDateFormatter
, moreover, it is used as the basis of the formatting component.getDateFormatWithLongYear
and see what happens. <?php foreach (['en_US', 'ru_RU', 'es_ES', 'fa_IR'] as $locale) { $dateFormat = (new \IntlDateFormatter( $locale, \IntlDateFormatter::SHORT, \IntlDateFormatter::NONE ))->getPattern(); $formatWithLongYear = preg_replace( '/(?<!y)yy(?!y)/', 'Y', $dateFormat ); $formatter = new \IntlDateFormatter( $locale, \IntlDateFormatter::NONE, \IntlDateFormatter::NONE, null, null, $formatWithLongYear ); echo $formatter->format(1455111783), PHP_EOL; }
2/10/2016 10.02.2016 10/2/2016 ۲۰۱۶/۲/۱۰ م.
getDateTimeFormat
is an obvious mistake. They concatenate date and time patterns. No, dudes, the order of displaying the date and time is not the same in all locales, we have already seen this above.intl
, I did - https://github.com/ksimka/intl_dtpg . This extension, which essentially implements a single function (as a function or class method) “find the most appropriate pattern for this set of parts of the date and time”. The same DateTimePatternGenerator::getBestPattern
(there are still a lot of interesting things in this class, but personally I’m critically missing only this method so far).intl
someone, or at least zadolbayte PHP developers requests. You can say that I forced you, threatening to force go
training.Source: https://habr.com/ru/post/278673/
All Articles