Этот ответ был обновлен с учетом щедрости.Оригинальный неотредактированный ответ находится ниже линии.
Почти все вопросы, добавленные владельцем щедрости, касаются того, как должны взаимодействовать даты и времени MySQL и PHP в контексте часовых поясов.
MySQL по-прежнему имеет жалкую поддержку часового пояса , что означает, что интеллект должен быть на стороне PHP.
- Установите свой MySQL подключение часового пояса к UTC, как указано в ссылке выше.Это приведет к тому, что все даты и время, обрабатываемые MySQL, включая
NOW()
, будут обрабатываться разумно. - Всегда использовать
DATETIME
, никогда не использовать TIMESTAMP
, если только вам явно не требуется специальное поведениев TIMESTAMP
.Это менее болезненно, чем раньше.
- Это ok для сохранения времени эпохи Unix в виде целого числа, если у вас есть , например, длянаследственные цели.Эпоха - UTC.
- Предпочитаемый формат даты и времени MySQL создается с использованием строки формата даты PHP
Y-m-d H:i:s
- Преобразование всех PHP даты в UTCпри их сохранении в MySQL, что довольно просто, как описано ниже
- Даты, возвращаемые из MySQL, можно безопасно передавать конструктору PHP DateTime.Обязательно укажите часовой пояс UTC!
- Конвертируйте PHP DateTime в локальный часовой пояс пользователя в echo , не раньше.К счастью, сравнение DateTime и математика по сравнению с другими DateTimes будет учитывать часовой пояс, в котором находится каждый из них.
- Вы по-прежнему согласны с прихотью базы данных DST, предоставляемой с PHP.Следите за обновлениями PHP и ОС!Держите MySQL в блаженном состоянии UTC, чтобы убрать одно потенциальное раздражение по летнему времени.
Обращается к большинству точек.
Последняя вещь - это doozy:
- Что делать, если кто-то уже вставил данные (например, с помощью
NOW()
), не беспокоясь о часовом поясе, чтобы убедиться, что все остается согласованным?
Это настоящее раздражение.Один из других ответов указал на MySQL CONVERT_TZ
, хотя я лично сделал бы это, переключаясь между часовым поясом сервера и UTC во время выбора и обновления, потому что я такой хардкорный.
приложение также должно иметь возможность устанавливать / выбирать DST соответственно для каждого пользователя.
Вам не нужно, а не должно делают это в современную эпоху.
Современные версии PHP имеют класс DateTimeZone , который включает в себя возможность перечислять именованные часовые пояса .Именованные часовые пояса позволяют пользователю выбирать свое фактическое местоположение, и система автоматически определяет свои правила перехода на летнее время на основе этого местоположения.
Вы можете комбинировать DateTimeZone с DateTime для некоторых простых, но мощных функций.Вы можете просто сохранить и использовать все ваших временных меток в UTC по умолчанию и преобразовать их в отображаемый часовой пояс пользователя.
// UTC default
date_default_timezone_set('UTC');
// Note the lack of time zone specified with this timestamp.
$nowish = new DateTime('2011-04-23 21:44:00');
echo $nowish->format('Y-m-d H:i:s'); // 2011-04-23 21:44:00
// Let's pretend we're on the US west coast.
// This will be PDT right now, UTC-7
$la = new DateTimeZone('America/Los_Angeles');
// Update the DateTime's timezone...
$nowish->setTimeZone($la);
// and show the result
echo $nowish->format('Y-m-d H:i:s'); // 2011-04-23 14:44:00
Используя эту техникусистема автоматически выберет правильные настройки DST для пользователя, не спрашивая пользователя, находятся ли они в настоящее время в DST.
Вы можете использовать аналогичный метод для отображения меню выбора.Вы можете непрерывно переназначать часовой пояс для одного объекта DateTime.Например, этот код перечислит зоны и их текущее время, на данный момент:
$dt = new DateTime('now', new DateTimeZone('UTC'));
foreach(DateTimeZone::listIdentifiers() as $tz) {
$dt->setTimeZone(new DateTimeZone($tz));
echo $tz, ': ', $dt->format('Y-m-d H:i:s'), "\n";
}
Вы можете значительно упростить процесс выбора с помощью некоторой магии на стороне клиента.Javascript имеет пятнистый, но функциональный класс дат со стандартным методом для получения смещения UTC в минутах .Вы можете использовать это, чтобы сузить список вероятных часовых поясов при слепом предположении, что часы пользователя правильные.
Давайте сравним этот метод с тем, чтобы сделать это самостоятельно.На самом деле вам нужно будет выполнять математику даты каждый раз, когда вы манипулируете датой-временем, в дополнение к тому, что вам не нужно выбирать пользователя, о котором он не будет беспокоиться.Это не просто неоптимально, это безумный бат-гуано.Заставление пользователей указывать, когда они хотят, чтобы поддержка DST вызывала проблемы и путаницу.
Кроме того, если вы хотите использовать для этого современные фреймворки PHP DateTime и DateTimeZone, вам необходимо использовать устаревшие Etc/GMT...
строки часовых поясов вместо именованных часовых поясов.Эти имена зон могут быть удалены из будущих версий PHP, поэтому было бы неразумно делать это.Я говорю все это из опыта.
tl; dr : Используйте современный набор инструментов, избавьте себя от ужасов даты математики.Предоставьте пользователю список с именем часовых поясов. Сохраните ваши даты в UTC , на которые DST никак не повлияет.Преобразуйте дату и время в выбранный пользователем часовой пояс на дисплее , не ранее.
В соответствии с запросом, приведен цикл по доступным часовым поясам, отображающий их смещение по Гринвичу в минутах.Я выбрал минуты здесь, чтобы продемонстрировать прискорбный факт: не все смещения в целых часах!Некоторые фактически переключаются на полчаса вперед во время летнего времени, а не на целый час.Результирующее смещение в минутах должно совпадать с Javascript Date.getTimezoneOffset
.
$utc = new DateTimeZone('UTC');
$dt = new DateTime('now', $utc);
foreach(DateTimeZone::listIdentifiers() as $tz) {
$local = new DateTimeZone($tz);
$dt->setTimeZone($local);
$offset = $local->getOffset($dt); // Yeah, really.
echo $tz, ': ',
$dt->format('Y-m-d H:i:s'),
', offset = ',
($offset / 60),
" minutes\n";
}