Работа с часовыми поясами в PHP - PullRequest
19 голосов
/ 07 декабря 2008

Некоторые проблемы с часовыми поясами в 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(), которая не учитывает часовой пояс, что позволяет my применять date() непосредственно к нему - таким образом применяя смещение часового пояса только один раз.

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

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

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

Ответы [ 4 ]

12 голосов
/ 08 декабря 2008

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

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

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

6 голосов
/ 30 января 2013

Начиная с 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');
1 голос
/ 07 декабря 2008

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

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

0 голосов
/ 11 июня 2013

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

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...