php date locale format
setlocale
(PHP 4, PHP 5, PHP 7, PHP 8)
setlocale — Устанавливает настройки локали
Описание
Альтернативная сигнатура (не поддерживается с именованными аргументами):
Устанавливает настройки локали.
Список параметров
Если в качестве locales передан массив, или после этого аргумента следуют дополнительные аргументы, функция будет использовать элементы массива или аргументы по порядку в качестве имён локали до тех пор, пока установка локали не будет успешной. Это удобно, если одна и та же локаль имеет разное имя в различных системах, или для создания запасного варианта при отсутствии какой-либо локали в системе.
Необязательные аргументы в виде строк или массивов для установки настроек локали до первой успешной попытки.
Каждый элемент массива пытается установить новую локаль до первой успешной попытки. Это полезно, если локаль известна под разными именами в разных системах или для обеспечения запасного варианта для возможно недоступного языкового стандарта.
На Windows setlocale(LC_ALL, ») устанавливает имена локалей из системных региональных/языковых настроек (доступных через Панель Управления).
Возвращаемые значения
Недопустимое имя категории также вызывает предупреждение. Имена локалей и категорий описаны в » RFC 1766 и » ISO 639. Разные системы имеют различные схемы именования локалей.
Примеры
Пример #1 Примеры использования setlocale()
Пример #2 Примеры использования setlocale() в Windows
Примечания
User Contributed Notes 31 notes
be careful with the LC_ALL setting, as it may introduce some unwanted conversions. For example, I used
setlocale (LC_ALL, «Dutch»);
to get my weekdays in dutch on the page. From that moment on (as I found out many hours later) my floating point values from MYSQL where interpreted as integers because the Dutch locale wants a comma (,) instead of a point (.) before the decimals. I tried printf, number_format, floatval. all to no avail. 1.50 was always printed as 1.00 🙁
When I set my locale to :
setlocale (LC_TIME, «Dutch»);
my weekdays are good now and my floating point values too.
I hope I can save some people the trouble of figuring this out by themselves.
If you are looking for a getlocale() function simply pass 0 (zero) as the second parameter to setlocale().
Beware though if you use the category LC_ALL and some of the locales differ as a string containing all the locales is returned:
?>
If you are looking to store and reset the locales you could do something like this:
?>
The above works here (Ubuntu Linux) but as the setlocale() function is just wrapping the equivalent system calls, your mileage may vary on the result.
It took me a while to figure out how to get a Finnish locale correctly set on Ubuntu Server with Apache2 and PHP5.
I had to install a finnish language pack with
«sudo apt-get install language-pack-fi-base»
The last thing you need to do after installing the correct language pack is restart Apache with «sudo apache2ctl restart». The locale «fi_FI.utf8» can then be used in PHP5 after restarting Apache.
setlocale(LC_MONETARY, ‘en_US’) doesn’t work anymore (at least in PHP Version 7.3.8).
I’ve used ‘en_US.UTF-8’ instead
//Fix encoding for russian locale on windows
$locale = setlocale(LC_ALL, ‘ru_RU.CP1251’, ‘rus_RUS.CP1251’, ‘Russian_Russia.1251’);
Pay attention to the syntax.
— UTF8 without dash (‘-‘)
— locale.codeset and not locale-codeset.
Stupid newbie error but worth knowing them when starting with gettext.
// for windows compatibility (e.g. xampp) : theses 3 lines are useless for linux systems
and ABSPATH is the absolute path to the locale dir
further note, under linux systems, it seems to be necessary to create the locale at os level using ‘locale-gen’.
The «locale» always depend on the server configuration.
i.e.:
When trying to use «pt_BR» on some servers you will ALWAYS get false. Even with other languages.
The locale string need to be supported by the server. Sometimes there are diferents charsets for a language, like «pt_BR.utf-8» and «pt_BR.iso-8859-1», but there is no support for a _standard_ «pt_BR».
This problem occours in Windows platform too. Here you need to call «portuguese» or «spanish» or «german» or.
But NEVER trust on that when making functions like date conversions or number formating. The best way to make sure you are doing the right thing, is using the default «en_US» or «en_UK», by not calling the setlocale() function. Or, make sure that your server support the lang you want to use, with some tests.
Remember that: Using the default locale setings is the best way to «talk» with other applications, like dbs or rpc servers, too.
For Windows users complaining about setlocale.
in short, if you want use for example: es_CO.UTF-8 it must be in Windows: Spanish_Colombia.1252
The code page 1252 is ISO-8859-1 (windows-1252 ANSI Latin 1; Western European (Windows)
Windows use different languages code from Unix, for example, es_CO becomes es-CO or Spanish_Colombia, also it doesn’t support UTF-8 charset as is shown in their website: https://msdn.microsoft.com/en-us/library/x99tb11d(v=vs.140).aspx
«The set of available locale names, languages, country/region codes, and code pages includes all those supported by the Windows NLS API except code pages that require more than two bytes per character, such as UTF-7 and UTF-8. If you provide a code page value of UTF-7 or UTF-8, setlocale will fail, returning NULL.»
Please check the updated website of language and code pages:
Here a copy paste in case the link is removed:
How do I format a date with a locale preferred date format with the actual month name?
I have a project using Yii that is built to support multiple languages. Using setlocale I can do the following:
This is almost what I need, however, I want to print out the actual name of the month in the preferred format not just the numbers. For example, for US English I’d like it to output:
And for French I’d like to output:
This has to work for whatever locale is provided (multiple countries) using the specific formatting rules for that locale, French in France and English are just examples. Is there a similar «automatic» way to do this with Yii or just php? Or do I need to save a formatting string along with the locale (not my preffered option)
2 Answers 2
Yii’s application object has a dateFormatter attribute that gives you access to a CDateFormatter object; you can use this object to format dates according to the application’s current language.
You can set this language inside your entry script, or you can defer it until some later point (still before you start generating content of course) such as your base controller’s init method.
In the above snippet, ‘long’ corresponds to the date format d MMMM y for the specified locale (Yii uses the CLDR specification for format strings; this preset is the equivalent of the %x specification in Yii terms) and null instructs the formatter to not include time information in the result at all.
You could also manually specify the format yourself if you wanted to:
strftime
(PHP 4, PHP 5, PHP 7, PHP 8)
strftime — Форматирует текущую дату/время с учётом текущих настроек локали
Описание
Список параметров
В отличие от ISO-9899:1999, в Sun Solaris воскресенью присваивается номер 1. Как результат, %u может работать не так, как описано в этом руководстве.
Только для Windows:
Модификаторы %z и %Z возвращают название часового пояса вместо смещения или аббревиатуры.
Только для macOS и Musl: модификатор %P не поддерживается в реализации этой функции в macOS.
Возвращаемые значения
Ошибки
Список изменений
Версия | Описание |
---|---|
8.0.0 | timestamp теперь допускает значение null. |
Примеры
Этот пример будет работать, если на вашей системе установлены соответствующие локали.
Пример #1 Пример использования функции strftime() с разными локалями
Пример #2 Пример номеров недели по ISO 8601:1988
Пример #3 Кроссплатформенный пример использования модификатора %e
// 1 января: выдаёт результат: ‘%e%1%’ (%%, e, %%, %e, %%)
$format = ‘%%e%%%e%%’ ;
Пример #4 Показываем все известные и неизвестные форматы.
// Результаты.
$strftimeValues = array();
Результатом выполнения данного примера будет что-то подобное:
Долгая история про локализацию даты без года в PHP
Пока неплохо. А теперь давайте слегка изменим условия: «вывести локализованную дату: там должен быть день и полное название месяца на языке локали». То есть, мы не хотим отображать год.
Желаемый результат выглядит так:
Вообще-то, теперь задача уже не так проста, как кажется.
Честно говоря, весь этот пост будет только и исключительно об этой задаче.
Погоди-погоди, а тебе это вообще зачем?
Некоторые, наверное, могут удивиться, какого вообще мне понадобился именно такой формат? Это довольно очевидно, если вы работаете с какой-то системой, имеющей отображение в виде ленты событий с отметками времени. Но если нет, давайте просто взглянем на Твиттер.
Если твит был опубликован недавно, Твиттер покажет вам грамотно отформатированный интервал времени. Если же твит случился давно, вы увидите грамотно отформатированную дату. Более того, если твит был опубликован в этом году, то года в этой дате не будет. И это отлично, это часть хорошего UX.
Идея в том, чтобы пользователи максимально быстро понимали, когда это случилось. Лишние данные это шум.
Теперь вы знаете, зачем. Вернёмся к нашей задаче.
Если вы немного подумаете, то станет ясно, что невозможно заранее определить константы для каждого кастомного формата, который когда-либо может прийти в голову разработчику, дизайнеру или менеджеру.
Ха, я только что придумал простое решение!
Напоминаю, что мы имеем.
Поэтому — нет, это даже и близко не решение. К слову, ничего стыдного в этом нет, это было и моим первым «быстрым решением».
Ладно, там есть паттерны, давайте используем паттерны!
Да, IntlDateFormatter в действительности внутри работает только с паттернами (константы форматов просто преобразуются в соответствующий паттерн), и при создании вы можете указать свой собственный.
Посмотрим… Похоже, нам нужен паттерн «d MMMM».
Выглядит отлично! Хотя постой, это ещё что за? Ох.
Напоминаю, мы хотим
Нет, ни фига не отлично, лишь одно совпадение. Всё потому, что паттерном вы указали не только части даты (день и месяц), но ещё и порядок, в котором они должны идти, и разделители. Как если бы вы сказали «сначала должен идти номер дня, затем полное название месяца, а между ними пробел». Для любой локали. Это полная ерунда.
Правда в том, что локаль это не только язык, это ещё и паттерн форматирования даты. И паттерн это не только что включить в результат, но также в каком порядке это расставить.
Смотрите, они все разные.
Но должно же быть готовое решение! Не может же быть, что его нет! Или.
вздох Да, я думал точно так же. Как это вообще возможно, что в PHP, во взрослом языке с развитой экосистемой и одним из мощнейших коммьюнити, может не быть какого-то базового функционала? Sad but true: возможно.
В intl отсутствует как минимум одна очень важная штука — DateTimePatternGenerator класс из ICU. Он сделан ровно для того, чтобы решать нашу маленькую задачку и все прочие подобные.
Стой-стой-стой, что ещё за ICU?
ICU это «International Components for Unicode» — компоненты интернационализации для юникода.
Цитаты с сайта ICU.
ICU is a mature, widely used set of C/C++ and Java libraries providing Unicode and Globalization support for software applications. ICU is widely portable and gives applications the same results on all platforms and between C/C++ and Java software.
Formatting: Format numbers, dates, times and currency amounts according the conventions of a chosen locale. This includes translating month and day names into the selected language, choosing appropriate abbreviations, ordering fields correctly, etc. This data also comes from the Common Locale Data Repository.
Короче, это такой крутой набор библиотек. Расширение intl само по себе никакой магии не умеет, это что-то типа прокси к этим библиотекам.
(В системе установлена версия 52.1, а PHP, как можно видеть выше, собран с 56.1. Это нормально.)
Ещё одна цитата с сайта ICU:
This class provides flexible generation of date format patterns, like «yy-MM-dd».
The user can build up the generator by adding successive patterns. Once that is done, a query can be made using a «skeleton», which is a pattern which just includes the desired fields and lengths. The generator will return the «best fit» pattern corresponding to that skeleton.
The main method people will use is getBestPattern(String skeleton), since normally this class is pre-built with data from a particular locale. However, generators can be built directly from other data as well.
Как это могло бы работать.
Результат (вероятно был бы таким):
Йуххху! Дадада, я тупо скопировал блок «желаемый результат». На самом деле я не знаю, что там будет, но я надеюсь, что будет так.
Так что делать, если я хочу прямо сейчас использовать кастомный формат?
В итоге я пришёл ко второму очевидному решению: нагенерить конфиг, содержащий каждый кастомный паттерн для каждой локали, которую поддерживает ваш проект. И делать это при появлении каждой новой локали.
Вот простой сниппет.
В итоге у вас будет что-то типа
Затем нужно вручную пройтись по всем этим строкам и удалить из них часть, отвечающую за отображение года.
Когда у вас десятки локалей, это становится изнурительной работой, ПРОСТО ПОВЕРЬТЕ МНЕ (слышится тихий плач).
И это ещё не всё. Если вам захочется выводить такую дату со временем, вам придётся нагенерить в два раза больше паттернов. Потому что нельзя просто взять и соединить отформатированные отдельно дату и время. Добавить время в конец даты, в начало или куда-то в середину?
Удаляем часть, ответственную за год, опять, да.
Но как все остальные в мире PHP делают это?
В это сложно поверить, но они либо вообще не парятся с локализацией дат, либо делают это неправильно.
Я заглянул в исходники нескольких CMS, сделанных на PHP.
Drupal
С первым же поиском я наткнулся на изумительный тикет с интригующим названием — «Date intl support is broken, remove it». Лолшто!? И это не шутка, они и правда это сделали.
Вообще, они решают задачу форматирования дат приблизительно так же (пачка кастомных конфигов)
, но до патча (смотрите на скриншот) там был ключ intl как раз для паттерна локализации. А теперь им просто пофиг.
Ещё, если я правильно понял (я не достаточно активный пользователь Друпала), каждый пользователь после установки CMS должен сам ручками прописать все эти паттерны. Для каждой локали. Ну, или там есть что-то такое, о чём я не знаю, но выглядит это именно так.
(Похоже, что они ещё не успели выпилить ключи intl из этой ветки)
Вообще, это не так уж плохо, но как пользователь CMS я нисколечки не хочу изучать все возможные культуры, чтобы выяснить, какие там у них принято использовать паттерны форматирования дат. Вся эта работа уже сделана в CLDR. Конечно, иногда мне нужны кастомные паттерны, но всё, на что я согласен, это указать, какие именно части даты и времени я хочу видеть в результате («только день и месяц, пожалуйста» или «будьте добры, мне бы месяц и время без секунд»).
WordPress
С WordPress у меня примерно те же отношения, я не из числа активных пользователей, поэтому я воспользовался поиском на Гитхабе. Похоже, что основная интересующая нас фунция здесь это date_i18n из functions.php (кстати, ребятушки, wtf? Файл с функциями из 5.2k строк кода? Серьёзно? У нас тут 2016-ый уже.).
Я честно потратил с полчаса, пытаясь понять, как оно работает. Но… но… да вы только гляньте на это.
Joomla!
Джумлу я вообще ни разу не трогал. Поэтому схема та же.
В итоге: почти то же самое, что и в Друпале, пачка предопределённых форматов, которые нужно задать для каждой локали.
ModX Revolution
strftime звучит чуть лучше, чем date_format (там есть форматы, которые дают ложное ощущение правильной локализации) или ничего, когда мы говорим о локализации, но и эта функция не делает то, что нам нужно.
Magento2
Magento это не CMS в общепринятом смысле, это e-commerce платформа, но она широко известна, и у неё даже есть отдельный собственный фреймворк. Поэтому чего бы и нет.
Но и их код не идеален. Смотрим в Timezone.php.
Я не смог найти места, в которых они бы пытались форматировать дату без года. Но есть ощущение, что они делают ту же ошибку, что и мы чуть ранее, пытаясь заменять год при форматировании «даты с длинным годом». Или же нет? Я не гуру регулярок (хоть и знаком с «lookahead» и «lookbehind»), поэтому я лучше просто выполню код из getDateFormatWithLongYear и посмотрю, что случится.
Похоже на успех! Ладно, иногда этот трюк срабатывает. Тут важнее сам факт того, что они вот так извращаются. Это ещё одно подтверждение, что в PHP не хватает того самого генератора паттернов.
А getDateTimeFormat это очевидная ошибка. Они конкатенируют паттерны даты и времени. Нет, чуваки, порядок отображения даты и времени не один и тот же во всех локалях, выше мы уже видели это.
Ещё можно заглянуть сюда. В любом случае — отличная работа, Magento!
Не хочешь ли ты сказать, что ты первый, кто заметил проблему?
Кстати, там нет защиты от CSRF
Критиковать любой может. Вот взял бы да сам и сделал!
Но проблема в том, что я не шарю ни в C++, ни в C. Поэтому используйте его на свой страх и риск (после внедрения у нас я расскажу, всё ли там хорошо). Расширение написано на C++ на базе PHPCPP методом examples+google+stackoverflow. Поэтому любые улучшения крайне приветствуются.
На этом всё. Спасибо, что дочитали до конца!
date — Форматирует вывод системной даты/времени
Описание
Список параметров
Шаблон результирующей строки ( string ) с датой. См. параметры форматирования ниже. Также существует несколько предопределенных констант даты/времени, которые могут быть использованы вместо этих параметров. Например: DATE_RSS заменяет шаблон ‘D, d M Y H:i:s’.
Возвращаемые значения
Ошибки
Список изменений
Версия | Описание |
---|---|
5.1.0 | Допустимым диапазоном дат для временных меток обычно являются даты с 13 декабря 1901, 20:45:54 GMT по 19 января 2038, 03:14:07 GMT. (Они соответствуют минимальному и максимальному значению 32-битного целого числа со знаком). Однако для PHP версии ниже 5.1.0 в некоторых операционных системах (например, Windows) этот диапазон был ограничен датами 01-01-1970 до 19-01-2038. |
5.1.0 |