Стандартное web-приложение работает минимум на двух машинами - браузере клиента и web-сервере с базой данных. Естественно что системное время на машинах может быть разным. Приложения которые безразличны к тому какое время у клиента очень распространены. Типичный пример где такие проблемы замечаются это форумы и социальные сети, что уж говорить о финансовых операциях.
Время на сервере (реальное)
Очевидно, что сохранять клиентское время в базу бессмысленно, потому что клиент может поменять временной пояс, или другие люди со своим часовым поясом могут запросить те же данные.
Можно попробовать до внесения данных установить на сервере часовой пояс клиента - в mysql это можно:
SET time_zone='+00:00'
Но как оказывается, время съезжает и мы получаем то же самое что и при сохранение клиентского времени:
CREATE TABLE `documents` ( `date_added` datetime default NULL )
SET time_zone='+00:00'; INSERT INTO test.documents (date_added) VALUES (NOW());
SET time_zone='+02:00'; INSERT INTO test.documents (date_added) VALUES (NOW());
SET time_zone='+00:00'; SELECT date_added FROM test.documents
Времена совершенно разные потому что съезжает не только системное время, но и времена всех данных. Как-то запутанно получается, но теперь мы точно уверены что SET time_zone - только для сервера и все данные должны быть в одной временной зоне, а клиенту надо показывать разные времена в зависимости от его временной зоны.
Однако есть магическая функция..
SELECT CONVERT_TZ(NOW(), @@session.time_zone, '+0:00'), NOW()
Разница в поясах
В любом случае разработчики стараются реализовать конвертирование на нескольких уровнях. Самое главное это конечно получить разницу во временных зонах. Это также можно реализовать несколькими способами:
- Спросить явно у пользователя при регистрации.
- Определить по IP при помощи гео-таргетинга.
- Использовать системное время клиента из javascript с сохранением в куки. Вот только использовать можно после первой загрузки.
document.cookie="offset=" + ( (new Date()).getTimezoneOffset()*60)*(-1)-'.abs(date('Z')).'; //js
echo date('d/m/Y H:i:s', time()+$_COOKIE['offset'] ); //php
Синхронизация
Задача действительно сложная, как вы вероятно и предполагали - везде где происходит обмен данных со временем прийдётся делать преобразование с поправкой на часовой пояс клиента.
Это можно сделать на стороне:
- Базы данных
- Простые INSERT и UPDATE запросы использующие локальное время (NOW, SYS_TIME и тп.) не меняются.
- Все SELECT запросы с датами должны использовать прямое преобразование во время клиента определёнными функциями (CONVERT_TZ) с учётом часового пояса.
- Сложные INSERT/UPDATE выражения, где дата явно указана надо обратно преобразовывать в локальное серверное время (или по гринвичу, как вам угодно хранить).
- Web-серверного приложения ( php )
- Если БД возвращает всё в локальном времени и ни один запрос не менялся, то прийдётся средствами php преобразовывать все данные. Timestamp повсюду - это хорошо, но не забывайте о DST.
- Внутренние php-переменные на основе системного времени теоретически можно сдвинуть устанавливая временную зону клиента, ведь зона сменяется только на время исполнения потока. Этот пункт полезен когда расчёт дат происходит с помощью timestamp'ов. Например для вычисления свободного времени (для пациента) при существующих записях занятого времени.
date_default_timezone_set("America/Los_Angeles");
putenv("TZ=US/Eastern"); //второй вариант
- Клиента
- Передавайте клиенту всё как раньше, но тогда прийдётся все времена менять в интерфейсе пользователя средствами javascript/flash. Тоесть все даты с часами и минутами в html выделяются отдельным скажем классом span элементов и после загрузки прибавляется разница в часовых поясах. Проблемы могут возникнуть с текстовыми "Сегодня/ в Феврале / 5 дней назад".
Читайте также
- PHP time zone solution
- Как конвертировать данные сервиса с датами между двумя серверами в разных часовых поясах
- Google ответы про timezones
- Карта часовых поясов
- Совы и жаворонки как следствие смены часовых поясов (в детстве?)
- Трудности с зонами в США, или что такое EST/EDT, CST/CDT и PST/PDT
Комментарии
Подскажи пожалуйста, более менее понятно как оприровать с зонами, но проблемма откуда их взять что бы показать пользователю, брать вручную из ссылки или можно повзаимствовать (не стащить) где нибудь уже готовое, должны же быть открытые базы
http://php.net/manual/en/timezones.php
http://dev.mysql.com/downloads/timezones.html
array( '-1' => '(GMT - 1:00) Азорские о-ва, о-ва Зеленого мыса', '-2' => '(GMT - 2:00) Среднеатлантическое время', '-3' => '(GMT - 3:00) Бразилия, Буэнос-Айрес, Джорджтаун, Гренландия', '-3.5'=> '(GMT - 3:30) Ньюфаундленд', '-4' => '(GMT - 4:00) Атлантическое время (Канада), Каракас, Ла Пас, Сантьяго', '-5' => '(GMT - 5:00) Восточное время (США и Канада), Богота, Лима, Кито', '-6' => '(GMT - 6:00) Центральное время (США и Канада), Мехико', '-7' => '(GMT - 7:00) Горное время (США и Канада), Аризона', '-8' => '(GMT - 8:00) Тихоокеанское время (США и Канада), Тихуана', '-9' => '(GMT - 9:00) Аляска', '-10' => '(GMT - 10:00) Гавайи', '-11' => '(GMT - 11:00) о.Мидуэй, Самоа', '-12' => '(GMT - 12:00) Эневеток, Кваджалейн', '0' => '(GMT) Касабланка, Дублин, Эдинбург, Лиссабон, Лондон, Монровия', '1' => '(GMT + 1:00) Амстердам, Берлин, Брюссель, Мадрид, Париж, Рим', '2' => '(GMT + 2:00) Каир, Хельсинки, Калининград, Южная Африка, Варшава', '3' => '(GMT + 3:00) Багдад, Эр-Рияд, Москва, Найроби', '3.5'=> '(GMT + 3:30) Тегеран', '4' => '(GMT + 4:00) Абу-Даби, Баку, Мускат, Тбилиси', '4.5'=> '(GMT + 4:30) Кабул', '5' => '(GMT + 5:00) Екатеринбург, Исламабад, Карачи, Ташкент', '5.5'=> '(GMT + 5:30) Бомбей, Калькутта, Мадрас, Нью-Дели', '6' => '(GMT + 6:00) Алма-Ата, Коломбо, Дхака, Новосибирск, Омск', '7' => '(GMT + 7:00) Бангкок, Ханой, Джакарта, Красноярск', '8' => '(GMT + 8:00) Пекин, Гонконг, Перт, Сингапур, Тайпей', '9' => '(GMT + 9:00) Осака, Саппоро, Сеул, Токио, Якутск', '9.5'=> '(GMT + 9:30) Аделаида, Дарвин', '10' => '(GMT + 10:00) Канберра, Мельбурн, Гуам, Сидней, Владивосток', '11' => '(GMT + 11:00) Магадан, Новая Каледония, Соломоновы о-ва', '12' => '(GMT + 12:00) Окленд, Фиджи, Камчатка, Веллингтон', '13' => '(GMT + 13:00) Камчатка', '14' => '(GMT + 14:00) Киритимати (остров Рождества)' )