Достаточно избитая во всевозможных блогах, в постах на хабре тема. Даже на офф сайте Mysql даны разъяснения и достаточно пруф линков. И все же есть несколько граблей, на который можно наступить, о которых мало где написано.
И так представим ситуацию, когда у нас есть алгоритм, например кеширования, который в своей основе проверяет время жизни закешированного ключа по некоторому логу в базе данных. Тогда мы напишем что-то вроде этого на псевдокоде, похожем на php
1 2 3 4 5 6 7 8 |
if ($result = Cache::get($hash)) { $timelimit = Model::get_timelimit(); if (time() >= $timelimit) { //делать запрос} else { //отдать из кеша } } |
Как-то так. И почему-то все запросы берутся из кеша, что мы видим в phpmemcachedadmin (если конечно используется memcached), но все равно задачи отрабатывают по полной.
Это скажем легкий пример, более простой когда просто приходится писать костыли, чтобы согласовать временные зоны сервера и php кода.
Конечно лучшим вариантом будет, когда есть доступ к root на серверах. Тогда, как советуют везде, есть несколько вариантов.
Установка временной зоны в php
1 2 3 |
if (function_exists('date_default_timezone_set')) date_default_timezone_set('Europe/Moscow'); |
или в php.ini
1 2 3 |
date.timezone = Europe/Moscow |
или в htaccess
1 2 3 |
php_value date.timezone “Europe/Moscow” |
А для mysql обычно советуют отправить запрос при инициализации приложения для установки time_zone.
1 2 3 4 |
SET GLOBAL time_zone = ‘Europe/Moscow’; $db->query("SET time_zone = 'Europe/Moscow'"); |
Так же иногда советуют добавить настройку в mysql/my.cnf
1 2 3 |
default-time-zone=’Europe/Moscow’ |
При этом подразумевается, что временные зоны выглядят как-то так: Europe/Moscow, Europe/Kiev.
Но это в том случае, если пользователь работает на хорошо настроенном хостинге.
При попытке установить default-time-zone=’Europe/Moscow’ можно поймать ошибку, что нету такой зоны. :)
Дело в том, что изначально параметр default-time-zone принимает значения вида “+06:00”, “-04:00”. А чтобы сработали человекопонятные названия зон, они должны быть занесены в таблицы mysql.time_zone*. Много их.
На офф сайте Mysql дает пояснения как заполнить их автоматически, если они не заполнены, с помощью утилиты.
И вот все вышеперечисленное было сделано. И вот все должно быть хорошо, даты пишутся с одинаковыми значениями по выводу date() в php и в табличках mysql.
А когда пытается отработать вышеприведенный пример с кешем, получается разница в час. Все дело в том, что при доставании из базы значения timelimit вызывается ф-я UNIX_TIMESTAMP(), которая приводит время в соответствии с системной временной зоной.
За этими всеми советами скрыто неведение, как же все таки устроены настройки временных зон в системе и mysql. Хотя с mysql уже понятно, а вот в системе (по крайней мере в debian) за зоны отвечает пакет tzdata. И не смотря на то, что по мануалу временные зоны были заполнены в mysql из системных
1 2 3 |
mysql_tzinfo_to_sql /usr/share/zoneinfo | mysql -u root -p |
все равно наблюдается расхождение на час. Дело все в том, что сервер может быть настроен на переход на “зимнее время”, отсюда все проблемы. Что же делать?
1 2 3 |
dpkg-reconfigure tzdata |
Теперь все будет работать правильно.