Работа с часовыми поясами в PHP

Некоторые проблемы с часовыми поясами в PHP уже давно задуманы, и мне было интересно, есть ли способы справиться с этим лучше, чем то, что я сейчас делаю.

Все вопросы связаны с изменением даты хранения базы данных:

Когда вы работаете с сайтом, который должен поддерживать несколько часовых поясов (для пользователей), чтобы нормализовать временную шкалу времени сохраненных временных меток, я всегда храню ее с часовым CURRENT_TIMESTAMP сервера, используя атрибут CURRENT_TIMESTAMP или функцию NOW() .

Таким образом, мне не нужно учитывать, какой временной интервал был задан для PHP, когда была введена метка времени (поскольку функции времени PHP зависят от часового пояса). Для каждого пользователя, в соответствии с его предпочтениями, я устанавливаю часовой пояс где-то в моем загрузочном файле, используя:

 date_default_timezone_set($timezone); 

Когда я планирую форматировать даты с помощью функции php date() , некоторая форма преобразования должна иметь место, поскольку MySQL в настоящее время хранит Ymd H:i:s метку в формате Ymd H:i:s . Без учета часовой пояс вы можете просто запустить:

 $date = date($format,strtotime($dbTimestamp)); 

Проблема заключается в том, что функции date() и strtotime() являются функциями, strtotime() , что означает, что если часовой пояс PHP установлен не так, как указано в часовом поясе сервера, смещение временной зоны будет применяться дважды (вместо одного раза, как хотелось бы).

Чтобы справиться с этим, я обычно извлекаю временные метки MySQL, используя UNIX_TIMESTAMP() которая не осведомлена о часовом поясе, что позволяет мне применять date() непосредственно к ней, тем самым применяя смещение часового пояса только один раз.

Мне не нравится этот «взлом», поскольку я больше не могу извлекать эти столбцы, как обычно, или использовать * для извлечения всех столбцов (иногда это упрощает запросы). Кроме того, иногда просто невозможно использовать UNIX_TIMESTAMP() (особенно при использовании с пакетами с открытым исходным кодом без значительной абстракции для состава запроса).

Другая проблема заключается в сохранении метки времени, когда использование CURRENT_TIMESTAMP или NOW() не является опцией – сохранение созданной PHP метки времени сохранит ее со смещением часового пояса, которое я бы хотел избежать.

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

Solutions Collecting From Web of "Работа с часовыми поясами в PHP"

Несколько месяцев назад мы некоторое время думали об этом. Техника, с которой мы закончили, довольно проста:

  1. Сохранять даты в GMT / UTC (например, 0 смещение временной зоны).
  2. Применять текущее смещение часового пояса пользователя после извлечения из базы данных (например, перед тем, как показывать пользователю или когда захотите).

Мы используем формат временных меток Unix. Но это не имеет значения.

Начиная с PHP 5.2 вы можете использовать DateTime, который упрощает работу с часовыми поясами:

 $datetime = new DateTime($dbTimestamp, $timezone); echo $datetime->format('Ymd H:i:s'); $datetime->setTimezone(new DateTimeZone('Pacific/Nauru')); echo $datetime->format('Ymd H:i:s'); 

Вы можете попробовать заставить MySQL использовать UTC везде, используя SET time_zone .

К сожалению, у меня нет ответа на предмет strtotime / UNIX_TIMESTAMP, на самом деле у меня такая же проблема с Postgres.

Я не нашел ни одного элегантного решения в сети, поэтому я создал сценарий генерации HTML-кода Timezone и вот результат напрямую. Это что-то вроде этого:

 <select name="timezone" id="timezone"> <optgroup label="UTC -11:00"> <option value="Pacific/Midway">UTC -11:00 Midway</option> <option value="Pacific/Niue">UTC -11:00 Niue</option> <option value="Pacific/Pago_Pago">UTC -11:00 Pago_Pago</option> </optgroup> <optgroup label="UTC -10:00"> <option value="America/Adak">UTC -10:00 Adak</option> <option value="Pacific/Honolulu">UTC -10:00 Honolulu</option> <option value="Pacific/Johnston">UTC -10:00 Johnston</option> <option value="Pacific/Rarotonga">UTC -10:00 Rarotonga</option> <option value="Pacific/Tahiti">UTC -10:00 Tahiti</option> </optgroup> . . . . . . . . . . . . . . <optgroup label="UTC +13:00"> <option value="Pacific/Apia">UTC +13:00 Apia</option> <option value="Pacific/Enderbury">UTC +13:00 Enderbury</option> <option value="Pacific/Fakaofo">UTC +13:00 Fakaofo</option> <option value="Pacific/Tongatapu">UTC +13:00 Tongatapu</option> </optgroup> <optgroup label="UTC +14:00"> <option value="Pacific/Kiritimati">UTC +14:00 Kiritimati</option> </optgroup> </select> 

Наслаждайтесь!