Подтвердить что ты не робот

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

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

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

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

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

date_default_timezone_set($timezone);

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

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

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

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

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

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

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

4b9b3361

Ответ 1

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

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

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

Ответ 2

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

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

Ответ 3

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

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

Ответ 4

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

<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>

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