Pull to refresh

Перевод часов в России, опять… и php5-intl

Reading time3 min
Views24K

Доброе %время суток%.

Предыстория


Ничего не предвещало беды. Задолго до были обновлены tzdata и всё, до чего могли руки дотянуться. Но в очередной момент перевода часов мой сайт стал выдавать московское время на час больше. Беглая проверка показала, что сама OS, mysql и php (функция date) возвращают время корректно и указывают часовой пояс +3 для Москвы. Собака же зарыта оказалась в хорошем расширении php5-intl. Функция format класса IntlDateFormatter упорно возвращала часовой пояс +4 для Москвы.

Исследование


В начале гугл не хотел мне помогать… но вскоре я узнал о таком звере, как icu и еще одной базе временных зон, которые, как ни странно, так и не были обновлены в моей системе. И всё бы хорошо… apt-get update… apt-get upgrade… и… отсутствие обновления для libicu фиг знает сколько времени. Даже хорошие люди баг завели в Debian по этому поводу. Но воз и ныне там. Гугл упорно ничего хорошего не советовал. Всё упиралось в ручную сборку свежей версии. Этот вариант даже был скромно освещен на хабре. Я, как человек далекий от мира Linux, чуть было не угробил систему в попытках что либо собрать. В итоге, с помощью хорошего друга lsh и совместного усиленного гугления мы нашли простой способ обновить данные для libicu не прибегая к компиляции или другим шаманствам.

Решение


Оказалось, что libicu, будучи даже скомпилированной с прямым включением данных таймзон и т.д. внутрь .so, оставляет возможность подсунуть свежую их версию через указания папки, откуда она могла бы их взять. Делается это через переменную окружения ICU_DATA. Найдя все кусочки пазла и пройдя пару неудачных попыток появилось простое и готовое к употреблению решение:

  • Необходимо скачать свежие версии данных таймзон и т.д. по ссылке с оф.сайта icu-project.
    Файлы необходимо взять из папочки «le» (little-endian, вероятно), по крайней мере именно они подошли мне на системе с Intel'овским процком и Debian x64. Там еще есть папочка «be» (big-endian) и загадочная «ee» (кто знает, для кого она?)
  • Разместить скаченные 4 файла в директорию, например: /opt/icu/icudt48l/ (для версии libicu 4.8)
  • Указать соответствующую переменную окружения:
    • Для php-cgi указать её можно в системном /etc/environment:
      ICU_DATA=/opt/icu/

    • Для php-fpm в настройках конкретного воркера:
      env[ICU_DATA]=/opt/icu/

    • Для Apache необходимо включить mod_env и в htaccess прописать:
      SetEnv ICU_DATA /opt/icu/


И, нет, я не ошибся разместив файлы в icu/icudt48l/ а в путях указав только папку icu. Всё дело в том, что libicu сам подставляет к пути ICU_DATA папку исходя из своей версии (зачем?!). Так что, в будущем, при обновлении libicu, папку придется переименовать в другое имя. Судя по наблюдением, название папки формируется как:
icudt - icu data
48 - версия libicu (4.8 -> 48, 3.6 -> 36)
l - порядок байт (l - little-endian, b - big-endian)
Соответственно папку вам необходимо называть исходя из версии libicu в вашей системе.

Перезапуск php-fpm и… профит ) теперь можно смело убрать костыль с подстановкой вместо Europe/Moscow таймзону Europe/Minsk :)

Кстати, вопрос, почему php-fpm игнорирует глобальный env? Если кто найдет способ указать глобально для всех воркеров php-fpm данную настройку, тому большое человеческое спасибо.
@symbix отмечает, что если в php-fpm выключить настройку clear_env, то и все воркеры php-fpm начнут видеть глобальный env, т.е. не придется для каждого воркера отдельно указывать env[ICU_DATA]. Но проблемой становится уже то, что как раз воркеры начинают видеть лишнего, а не только нужную нам строку.


Как ни странно, но этот простой способ было сложно нагуглить. Я, как и многие до меня, столкнувшись с этой проблемой, пытались пересобирать, вытаскивать из свежих тестовых сборок дистрибутивов и много еще чего. И что еще более странно, так это то, что данный способ только мельком упоминается на сайте самих icu. Надеюсь я закрыл для вас этот вопрос.

Спасибо и безбажного вам кодинга!
Tags:
Hubs:
Total votes 34: ↑31 and ↓3+28
Comments23

Articles