#Симптомы, область применения и причины
PHP IntlDateFormatter выводит месяцы и дни недели на другом языке после переноса или обновления сервера. Как проверить переданную локаль, часовой пояс, шаблон и версию ICU. IntlDateFormatter использует ICU, а не просто системную локаль оболочки. Значения locale, timezone, calendar и pattern при создании форматтера влияют на конечный текст независимо от языка страницы HTML.
| Возможная причина | Как узнать | Что делать |
|---|---|---|
| Локаль не задана явноВ конструкторе используется значение по умолчанию, зависящее от окружения приложения. | Один сервер показывает английские месяцы, другой русские. | Передать ожидаемую локаль явно, например ru_RU. |
| Шаблон или часовой пояс формируют неожиданную датуВ функции вручную указаны поля или зона, отличающаяся от настроек проекта. | Язык верен, но дата сдвинута на день либо используется неподходящая форма месяца. | Проверить timezone и соответствующий стиль/шаблон. |
| Версии ICU отличаютсяСведения CLDR и склонения названий месяцев могут меняться между версиями ICU. | После обновления сервера появилась другая формулировка при тех же параметрах. | Сравнить значения Intl и зафиксировать требуемое представление тестом. |
#Безопасная диагностика и пошаговое исправление
- Сохраните реальный пример неверной датыОткройте страницу, где видна проблема, и запишите исходную дату-время, ожидаемое значение на русском и фактически выведенный текст. Отдельно отметьте, неверны ли только слова или ещё и календарный день. Не делайте вывод о сломанной локали, если проблема лишь в переносе времени через полночь: это, скорее всего, часовой пояс.
- Найдите место создания форматтераВ редакторе кода выполните поиск по
new IntlDateFormatter(иdatefmt_create(. Просмотрите аргументы: locale, тип даты, тип времени, timezone, calendar и при наличии pattern. Если локаль получена из HTTP-заголовка пользователя, проверьте её допустимость и ожидаемое значение для тестового запроса. Не подменяйте язык приложения глобальной сменой параметров ОС.
- Проверьте расширение Intl именно для сайтаВ панели параметров PHP убедитесь, что расширение intl включено для версии PHP, обслуживающей сайт. В терминале можно выполнить
php -mдля CLI и найти intl, но этот результат не описывает другие версии PHP-FPM. Если в браузере естьClass "IntlDateFormatter" not found, это уже отсутствие расширения, а не ошибка локали; попросите администратора подключить совместимый модуль через панель. - По SSH в терминале Linux, обычные праваLinux · Терминал (Bash)КомандаПо SSH в терминале Linux, обычные права. Список модулей относится только к PHP командной строки.
php -m
- Задайте локаль и часовой пояс явно в диагностическом примереВ тестовой копии приложения вызовите
IntlDateFormatterс явными параметрамиru_RUиEurope/Moscowлибо актуальной зоной вашего проекта. Не копируйте чужой часовой пояс в рабочий код без сопоставления требований сайта. Используйте фиксированную дату, чтобы сравнить результат с двумя серверами при одинаковом входе. - Пример кода по темеPHPТолько тестовый пример; для своего проекта замените часовой пояс на требуемый, а вывод не оставляйте публичным диагностическим маршрутом.
<?php $dt = new DateTimeImmutable('2026-01-15 12:00:00', new DateTimeZone('Europe/Moscow')); $fmt = new IntlDateFormatter('ru_RU', IntlDateFormatter::LONG, IntlDateFormatter::NONE, 'Europe/Moscow', IntlDateFormatter::GREGORIAN); echo $fmt->format($dt);
- Разделите локаль и параметры шаблонаЕсли простой пример правильно показывает русский месяц, вернитесь к шаблону реальной страницы. У
setPatternи аргументаpatternправила ICU; буквальные части и различия контекста месяца (MMMM/LLLL) меняют форму слова. Для отображения в русском падежах не пытайтесь исправлять результат перебором системных переменных; выберите подходящий шаблон и проверьте ожидаемое грамматическое употребление.
- Сопоставьте ICU, PHP и часовую зону разных серверовВ тестовом журнале приложения запросите
INTL_ICU_VERSION,IntlDateFormatter::getLocale()иdate_default_timezone_get(). Не публикуйте полныйphpinfo()в интернете. Если ICU отличается, изменения в лингвистических данных возможны и не обязательно являются ошибкой; для точного текста страницы лучше покрыть форматирование тестом. При разных датах независимо проверьте источник UNIX-времени и timezone. - Исполнять после создания переменной $fmt в защищённом тестовом маршрутеPHPИсполнять после создания переменной $fmt в защищённом тестовом маршруте. После проверки убрать журналирование.
<?php error_log('ICU='.INTL_ICU_VERSION); error_log('PHP timezone='.date_default_timezone_get()); error_log('formatter locale='.$fmt->getLocale());
- Исправьте код с возможностью откатаВнесите явную локаль и пояс или скорректируйте шаблон в одном месте проекта. Сохраните предыдущую версию файла и набор контрольных дат (первое число месяца, конец года, дата около полуночи). Прогоните тесты, затем разверните обновление штатным способом. Не меняйте locale для всех пользователей, если сайт многоязычный.
- Проверьте результат на двух датах и двух языкахДля русского интерфейса убедитесь, что месяцы отображаются по-русски и день не смещён. Если сайт многоязычный, повторите для английского или другого поддерживаемого языка и проверьте, что изменение не затронуло его. При неуспехе верните прежний файл из копии и приложите к заявке значения locale, timezone, ICU и исходные контрольные даты.
#Как проверить результат и что делать дальше
Успех — одинаковый исходный момент времени даёт ожидаемые дату, язык и форму месяца на целевой версии PHP/ICU без нарушения других локалей. Если видите другой день, продолжайте диагностику часового пояса отдельно от перевода.