Некоторые проблемы с часовыми поясами в 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 метки времени сохранит ее со смещением часового пояса, которое я бы хотел избежать.
Я, вероятно, отсутствует кое-что действительно основное здесь, но до сих пор я не смог придумать общее решение для решения этих проблем, поэтому я вынужден рассматривать их в каждом конкретном случае. Ваши мысли очень приветствуются
Несколько месяцев назад мы некоторое время думали об этом. Техника, с которой мы закончили, довольно проста:
Мы используем формат временных меток 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>
Наслаждайтесь!