Использование часовых поясов в веб-приложении PHP
Я уже несколько часов ищу, как лучше всего использовать часовые пояса в веб-приложении PHP/MySQL, найти окончательный ответ сложно. Из того, что я узнал до сих пор, лучше всего хранить все вещи в базе данных в UTC (поправьте меня, если я ошибаюсь).
когда пользователь регистрируется, я спрошу их о часовом поясе, а затем сохраню это против пользователя. Это будет в этом формате в виде выпадающего меню:
<option value="Europe/London">(GMT) Greenwich Mean Time : London</option>
приложение, которое я строю позволит пользователям устанавливать договоренности в будущем с людьми (встречи), так же, как календарь. Очевидно, что в течение года разные часовые пояса имеют разные периоды летнего времени, любая идея, как я буду обслуживать это?
скажем, пользователь из Великобритании устанавливает встречу на 3:00 вечера 24 января 2013 года и приглашает кого-то, кто живет в Калифорнии, на эту встречу, как мне ее получить, чтобы американец видел эту встречу в своем часовом поясе, а пользователь Великобритании видел ее в своем часовом поясе? (Обратите внимание, что оба пользователя подписаны и установили свой часовой пояс).
есть ли у кого четкое объяснение и, возможно, некоторые примеры для этого? Или можете указать мне, где я могу это найти?
спасибо
2 ответов
я подробно рассмотрел эту ситуацию в приложении PHP/MySQL, которое я написал для частного оператора jet чуть более года назад. Существуют различные стратегии для обработки часовых поясов на этих двух платформах, но я объясню, как я это сделал. Я устанавливаю сервер MySQL в UTC и запускаю каждый PHP-скрипт в часовом поясе, который пользователь указывает во время процесса регистрации для профиля пользователя.
MySQL и PHP (PHP 5.2 и выше) имеют собственные типы данных datetime. В MySQL datetime-это примитивный тип данных, в то время как PHP 5.2 и выше предлагает встроенный класс DateTime. Тип данных MySQL datetime не включает метаданные для часового пояса, но объект PHP DateTime всегда включает часовой пояс. Если конструктор PHP datetime не указывает необязательный часовой пояс во втором аргументе, то конструктор PHP datetime использует переменную среды php.
и MySQL, и PHP имеют часовой пояс по умолчанию, установленный в файлах конфигурации. MySQL использует the datetime в конфигурационном файле для каждого соединения БД, если пользователь не указывает другой часовой пояс после запуска соединения с помощью команды SET time_zone = [timezone];
. PHP также устанавливает переменную среды часового пояса для каждого скрипта, используя часовой пояс, установленный в файле конфигурации сервера, и эта переменная среды может быть переопределена с помощью функции PHP date_default_timezone_set()
после запуска скрипта.
класс PHP DateTime имеет свойство, называемое часовой пояс, который является объект PHP DateTimeZone. Объект DateTimeZone задается с помощью строки для точного часового пояса. The список часовых поясов является всеобъемлющим, имея сотни отдельных часовых поясов по всему миру. часовые пояса PHP будут автоматически учитывать летнее время.
когда пользователь генерирует datetime в веб-приложении, создайте объект PHP datetime в часовом поясе профиль пользователя. Тогда используйте setTimezone
метод для изменения объекта DateTime в часовой пояс UTC. Теперь у вас есть datetime пользователя в UTC, и вы можете сохранить значение в базе данных. Используйте DateTime format
метод для выражения данных в виде строки в формате, принятом MySQL.
таким образом, пользователь генерирует datetime, и вы делаете объект PHP datetime в указанном часовом поясе пользователя:
// set using an include file for user profile
$user_timezone = new DateTimeZone('America/New_York');
// 1st arg in format accepted by PHP strtotime
$date_object1 = new DateTime('8/9/2012 5:19 PM', $user_timezone);
$date_object1->setTimezone(new DateTimeZone('UTC'));
$formated_string = $date_object1->format('Y-m-d H:i:s');
$query_string="INSERT INTO `t_table1` (`datetime1`) VALUES('$formated_string')";
при получении значения из базы данных постройте в формате UTC, а затем преобразуйте в часовой пояс пользователя.
$query_string="SELECT `datetime1` FROM `t_table1`";
$date_object1=new DateTime($datetime_string_from_mysql, new DateTimeZone('UTC');
$date_object1->setTimezone($user_timezone);
$string_for_display_in_application = $date_object1->format('m/d/Y g:i a');
используя этот метод, ваши значения datetime всегда хранятся в UTC внутри БД, и пользователь всегда испытывает значения в часовом поясе своего профиля. PHP будет корректировать летнее время, если это необходимо для каждого часового пояса.
One gotcha: это объяснение не охватывает тип данных метки времени MySQL. Я рекомендую использовать тип данных MySQL datetime для хранения datetime значения, а не тип данных timestamp. Тип данных timestamp рассматривается в руководстве здесь.
Edit: Вы можете создать массив, содержащий каждую строку часового пояса PHP, используя listIdentifiers, который является статическим методом класса DateTimeZone.
в MySQL, что вам нужно сделать, это:
- храните выбранный часовой пояс каждого пользователя в том месте, где вы можете его получить, когда выполняете запросы к базе данных от имени этого пользователя. Вы можете сохранить его как строку.
- прямо перед тем, как вы работаете от имени конкретного пользователя (например, хранение или получение времени и даты встречи), сделайте
SET time_zone = (stored time zone setting)
это приведет к тому, что часовые пояса будут соответствующим образом преобразованы в локальные время.
Edit:
это работает, потому что
- MySQL пытается использовать UTC (универсальное время, ранее известное как среднее время Гринвича) для хранения элементов данных DATETIME и TIMESTAMP в таблицах.
- он может только сделать это правильно, если он знает правильный часовой пояс для каждого элемента данных приведены в приложениях.
- в приложениях, которые не заботятся о разных часовых поясах, он делает это в MySQL-server-wide способом. См.https://dev.mysql.com/doc/refman/5.5/en/time-zone-support.html . Большинство людей, которые запускают приложения с несколькими национальными и несколькими часовыми поясами, устанавливают свои часовые пояса сервера в UTC, а не в местное время, потому что это делает его много легче держать вещи в порядке.
- очень мало смысла пытаться конвертировать время из UTC в местное время, если вы также не знаете дату и часовой пояс, потому что местное время включается и выключается в разное время года. Просто попытайтесь сделать это правильно для всех трех Израиля, Аризоны и Нью-Йорка, я смею вас! Израиль переключается между дневным и стандартным временем на Пасху и Рош-Ха-Шана; Аризона не переключается, а Нью-Йорк переключается по прихоти федерального законодательного органа США.
- существует настройка time_zone области сеанса (
SET time_zone = something
). Если вы не установите его, он использует представление часового пояса в пункте 3 выше. Если вы установите его, сервер будет использовать его в качестве часового пояса для преобразования своего внутреннего представление в представление, которое оно отправляет обратно в запросах. - вы можете получить список имен доступных часовых поясов на вашем сервере MySQL, выдав
SELECT Name from mysql.time_zone_name
. Это может заполнить выпадающее меню, из которого пользователь может выбрать свой часовой пояс. Если этот запрос не возвращает элементов, посмотрите в нижней частиhttps://dev.mysql.com/doc/refman/5.5/en/time-zone-support.html .
таким образом, это означает, что вы можете установить настройку time_zone сеанса в зону конкретного пользователя, а затем вернуться в часовом поясе этого пользователя. Кроме того, любой DATETIME
или TIMESTAMP
товары вы INSERT
или UPDATE
будет преобразован из часового пояса этого пользователя во внутреннее представление MySQL, поскольку они размещены в ваших таблицах.
будьте осторожны: в веб-приложениях с постоянными соединениями MySQL работа для нового запроса пользователя наследует настройку time_zone соединения. Не забудьте сбросить его для нового пользователя.
если вы запуск запроса, возвращающего данные локального времени для более чем одного пользователя, и эти пользователи находятся в разных часовых поясах, вы не можете воспользоваться этим набором функций MySQL за сеанс. Вы можете обойти это, запустив различные запросы для разных пользователей и изменив настройку time_zone между ними.
или, вы можете использовать функцию MySQL
CONVERT_TZ(datetime,'UTC','user_time_zone')
или аналогичный по каждому пункту.
альтернативно, Java и DotNET имеют свой собственный высококачественный часовой пояс манипуляционные системы. Таким образом, вы можете сделать выбор запуска сервера MySQL с настройкой time_zone UTC и выполнить все преобразования часового пояса в своем приложении.