Летнее время и лучшие часовые пояса
Я надеюсь сделать этот вопрос и ответы на него исчерпывающим руководством по работе с переходом на летнее время, в частности по фактическим изменениям.
Если у вас есть что добавить, пожалуйста
Многие системы зависят от сохранения точного времени, проблема заключается в изменениях времени из-за перехода на летнее время - перемещения часов вперед или назад.
Например, в системе приема заказов есть бизнес-правила, которые зависят от времени заказа - если часы изменятся, правила могут быть не такими ясными. Как сохранить время заказа? Есть, конечно, бесконечное количество сценариев - это просто иллюстративный.
- Как вы справились с проблемой перехода на летнее время?
- Какие предположения являются частью вашего решения? (ищите контекст здесь)
Как важно, если не больше так:
- Что ты пробовал, чтобы не получилось?
- Почему это не сработало?
Я был бы заинтересован в программировании, ОС, сохранности данных и других соответствующих аспектах проблемы.
Общие ответы отличные, но я также хотел бы увидеть детали, особенно если они доступны только на одной платформе.
30 ответов
Резюме ответов и других данных: (пожалуйста, добавьте свои)
Делать:
- Всякий раз, когда вы говорите о точном моменте времени, сохраняйте время в соответствии с единым стандартом, на который не влияет переход на летнее время. (GMT и UTC эквивалентны в этом отношении, но предпочтительнее использовать термин UTC. Обратите внимание, что UTC также называется Zulu или Z time.)
- Если вместо этого вы выберете сохранение времени с использованием значения местного времени, включите смещение местного времени для этого конкретного времени из UTC (это смещение может изменяться в течение года), чтобы впоследствии можно было однозначно интерпретировать метку времени.
- В некоторых случаях вам может потребоваться сохранить время UTC и эквивалентное местное время. Часто это делается с двумя отдельными полями, но некоторые платформы поддерживают
datetimeoffset
Тип, который может хранить оба в одном поле. - При хранении меток времени в виде числового значения используйте время Unix - это число целых секунд с
1970-01-01T00:00:00Z
(без учета високосных секунд). Если вам требуется более высокая точность, используйте вместо этого миллисекунды. Это значение всегда должно основываться на UTC, без какой-либо настройки часового пояса. - Если впоследствии вам может понадобиться изменить временную метку, включите исходный идентификатор часового пояса, чтобы вы могли определить, изменилось ли смещение относительно исходного записанного значения.
- При планировании будущих событий обычно предпочтительнее местное время, а не UTC, поскольку смещение обычно меняется. Смотрите ответ и сообщение в блоге.
- При сохранении целых дат, таких как дни рождения и годовщины, не конвертируйте в UTC или любой другой часовой пояс.
- По возможности сохраняйте данные только для даты, которые не включают время суток.
- Если такой тип недоступен, обязательно всегда игнорируйте время суток при интерпретации значения. Если вы не можете быть уверены в том, что время суток будет игнорироваться, выберите 12:00 полдень, а не 00:00 полночь в качестве более безопасного репрезентативного времени в этот день.
- Помните, что смещения часового пояса не всегда являются целым числом часов (например, индийское стандартное время - UTC+05:30, а Непал использует UTC+05:45).
- Если вы используете Java, используйте java.time для Java 8 и новее.
- Большая часть этой функциональности java.time перенесена в Java 6 & 7 в библиотеке ThreeTen-Backport.
- Далее адаптирован для ранней версии Android (< 26) в библиотеке ThreeTenABP.
- Эти проекты официально вытесняют почтенную Joda-Time, теперь в режиме обслуживания. Классы Joda-Time, ThreeTen-Backport, ThreeTen-Extra, java.time и JSR 310 возглавляет один и тот же человек, JodaStephen.
- Если вы используете .NET, рассмотрите возможность использования Noda Time.
- Если вы используете.NET без Noda Time, учтите, что
DateTimeOffset
часто лучший выбор, чемDateTime
, - Если вы используете Perl, используйте DateTime.
- Если вы используете Python, используйте pytz или dateutil.
- Если вы используете JavaScript, используйте moment.js с расширением http://momentjs.com/time zone/.
- Если используется PHP > 5.2, используйте собственные преобразования часовых поясов, предоставляемые
DateTime
, а такжеDateTimeZone
классы. Будьте осторожны при использованииDateTimeZone::listAbbreviations()
- см. ответ. Чтобы поддерживать PHP в актуальном состоянии с данными Олсона, периодически устанавливайте PECL-пакет time zonedb; смотри ответ. - Если вы используете C++, обязательно используйте библиотеку, которая правильно использует базу данных часовых поясов IANA. К ним относятся cctz, ICU и библиотека "tz" Говарда Хиннанта.
- Не используйте Boost для преобразования часовых поясов. Хотя его API утверждает, что поддерживает стандартные идентификаторы IANA (он же "zoneinfo"), он грубо сопоставляет их с данными в стиле POSIX, не учитывая богатую историю изменений, которые могла иметь каждая зона. (Также файл вышел из строя.)
- Если вы используете Rust, используйте Chrono.
- Большинство бизнес-правил используют гражданское время, а не UTC или GMT. Поэтому планируйте преобразовывать временные метки UTC в местный часовой пояс перед применением логики приложения.
- Помните, что часовые пояса и смещения не являются фиксированными и могут меняться. Например, исторически США и Великобритания использовали одни и те же даты, чтобы "прыгнуть вперед" и "отступить". Тем не менее, в 2007 году США изменили даты, на которые меняются часы. Теперь это означает, что в течение 48 недель в году разница между лондонским и нью-йоркским временем составляет 5 часов, а в течение 4 недель (3 весной, 1 осенью) - 4 часа. Будьте внимательны к таким элементам в любых вычислениях, которые включают несколько зон.
- Рассмотрите тип времени (фактическое время события, время вещания, относительное время, историческое время, повторяющееся время), какие элементы (временная метка, смещение часового пояса и имя часового пояса) вы должны сохранить для правильного поиска - см. "Типы времени" в этот ответ
- Синхронизируйте файлы tzdata вашей ОС, базы данных и приложений между собой и остальным миром.
- На серверах установите аппаратные часы и часы ОС на UTC, а не на местный часовой пояс.
- Независимо от предыдущего пункта, серверный код, включая веб-сайты, никогда не должен ожидать, что локальный часовой пояс сервера будет чем-то конкретным. смотри ответ.
- Предпочитаю работать с часовыми поясами в каждом конкретном случае в коде приложения, а не глобально с помощью настроек или настроек файла конфигурации.
- Используйте сервисы NTP на всех серверах.
- При использовании FAT32 помните, что временные метки хранятся по местному времени, а не по UTC.
- При работе с повторяющимися событиями (например, еженедельным телешоу) помните, что время меняется в зависимости от летнего времени и будет различным в разных часовых поясах.
- Всегда запрашивать значения даты и времени как включающие нижнюю границу, исключающие верхнюю границу (
>=
,<
).
Не рекомендуется :
- Не путайте "часовой пояс", такой как
America/New_York
со смещением часового пояса, таким как-05:00
, Это две разные вещи. Смотрите тег часового пояса вики. - Не используйте JavaScript
Date
объект для выполнения вычислений даты и времени в старых веб-браузерах, так как ECMAScript 5.1 и ниже имеет недостаток дизайна, который может неправильно использовать переход на летнее время. (Это было исправлено в ECMAScript 6 / 2015). - Никогда не доверяй часам клиента. Это может быть очень неправильно.
- Не говорите людям "всегда используйте UTC везде". Этот широко распространенный совет близок к нескольким действительным сценариям, которые описаны ранее в этом документе. Вместо этого используйте соответствующую временную привязку для данных, с которыми вы работаете. (Временная метка может использовать UTC, но не следует использовать будущее расписание и значения только для даты.)
Тестирование:
- При тестировании убедитесь, что вы тестируете страны в Западном, Восточном, Северном и Южном полушариях (фактически в каждой четверти земного шара, а значит, в 4 регионах), причем в настоящее время идет как ТЛЧ, а не (дает 8), так и страна, которая это делает. не использовать DST (еще 4, чтобы охватить все регионы, в сумме 12).
- Проверьте переход на летнее время, т. Е. Когда вы находитесь в летнее время, выберите значение времени из зимы.
- Тестируйте граничные случаи, такие как часовой пояс UTC+12 с DST, делая местное время UTC+13 летом и даже места с UTC+13 зимой
- Протестируйте все сторонние библиотеки и приложения и убедитесь, что они правильно обрабатывают данные часового пояса.
- Тестируйте получасовые часовые пояса, по крайней мере.
Ссылка:
- Подробный
timezone
тег вики-страницы на переполнение стека - База данных Олсона, она же Tz_database
- Проект IETF для ведения базы данных Olson
- Источники для часового пояса и летнего времени
- Формат ISO (ISO 8601)
- Сопоставление базы данных Olson и идентификаторов часовых поясов Windows от консорциума Unicode
- Страница часового пояса в Википедии
- Помеченные вопросы Stack Overflow
dst
- Помеченные вопросы Stack Overflow
timezone
- Работа с DST - лучшие практики Microsoft DateTime
- Сетевой протокол времени в Википедии
Другой:
- Лоббировать вашего представителя, чтобы положить конец мерзости, которая является DST. Мы всегда можем надеяться...
- Лобби по стандартному времени Земли
Я не уверен, что я могу добавить к ответам выше, но вот несколько моментов от меня:
Типы времени
Есть четыре разных момента, которые вы должны рассмотреть:
- Время события: например, время, когда происходит международное спортивное событие, или коронация / смерть / и т.д. Это зависит от часового пояса события, а не от зрителя.
- Телевизионное время: например, конкретное телевизионное шоу транслируется в 21:00 по местному времени по всему миру. Важно подумать о публикации результатов (скажем, American Idol) на вашем сайте
- Относительное время: например: этот вопрос закрывается за 21 час. Это легко отобразить
- Время повторения: например: ТВ-шоу каждый понедельник в 21:00, даже если меняется летнее время.
Существует также историческое / альтернативное время. Это раздражает, потому что они не могут вернуться к стандартному времени. Например: Юлианские даты, даты в соответствии с лунным календарем на Сатурне, клингонским календарем.
Хранение времени начала / окончания в UTC работает хорошо. Для 1 вам нужно имя часового пояса события + смещение, сохраненное вместе с событием. Для 2 вам нужен локальный идентификатор времени, сохраненный для каждого региона, и имя локального часового пояса + смещение, сохраненное для каждого зрителя (это можно получить из IP, если вы находитесь в затруднительном положении). В течение 3 храните в секундах UTC и не требуйте часовых поясов. 4 - это особый случай 1 или 2, в зависимости от того, является ли это глобальным или локальным событием, но вам также необходимо сохранить созданное с отметкой времени, чтобы вы могли определить, изменилось ли определение часового пояса до или после создания этого события. Это необходимо, если вам нужно показать исторические данные.
Время хранения
- Всегда хранить время в UTC
- Преобразовать в местное время на дисплее (местное определяется пользователем, смотрящим на данные)
- При сохранении часового пояса вам нужно имя, временная метка и смещение. Это необходимо, потому что правительства иногда изменяют значения своих часовых поясов (например, правительство США изменило даты перехода на летнее время), и ваше приложение должно обрабатывать вещи изящно... например: точная временная метка, когда эпизоды LOST показывали как до, так и после правил перехода на летнее время изменилось.
Смещения и имена
Примером вышеупомянутого будет:
Финал кубка мира по футболу состоялся в ЮАР (UTC+2- SAST) 11 июля 2010 года в 19:00 UTC.
С помощью этой информации мы можем исторически определить точное время, когда проходил финал WCS 2010 года, даже если определение часового пояса Южной Африки изменилось, и иметь возможность отображать его зрителям в их местном часовом поясе в тот момент, когда они запрашивают базу данных.
Системное время
Вам также необходимо поддерживать синхронизацию файлов tzdata вашей ОС, базы данных и приложений как между собой, так и с остальным миром, а также проводить тщательные испытания при обновлении. Не случайно, что стороннее приложение, от которого вы зависите, неправильно обрабатывает изменения TZ.
Убедитесь, что аппаратные часы настроены на UTC, и если вы используете серверы по всему миру, убедитесь, что их операционные системы также настроены на использование UTC. Это становится очевидным, когда вам нужно скопировать почасово повернутые файлы журнала apache с серверов в нескольких часовых поясах. Сортировка их по имени файла работает, только если все файлы имеют одинаковый часовой пояс. Это также означает, что вам не нужно вычислять дату в своей голове, когда вы переходите из одного окна в другое, и вам нужно сравнивать временные метки.
Также запустите ntpd на всех компьютерах.
клиенты
Никогда не доверяйте отметке времени, полученной с клиентского компьютера, как действительной. Например, Date: HTTP-заголовки или JavaScript Date.getTime()
вызов. Это хорошо, когда они используются в качестве непрозрачных идентификаторов или когда выполняются вычисления даты во время одного сеанса на одном и том же клиенте, но не пытайтесь связывать эти значения с чем-то, что есть на сервере. Ваши клиенты не запускают NTP и могут не обязательно иметь работающую батарею для своих часов BIOS.
пустяки
Наконец, правительства иногда делают очень странные вещи:
Стандартное время в Нидерландах было ровно на 19 минут и на 32,13 секунды больше, чем UTC по закону с 1909-05-01 по 1937-06-30. Этот часовой пояс не может быть точно представлен в формате ЧЧ: ММ.
Хорошо, я думаю, что я закончил.
Это важный и удивительно сложный вопрос. Правда в том, что не существует полностью удовлетворяющего стандарта для постоянного времени. Например, стандарт SQL и формат ISO (ISO 8601) явно недостаточны.
С концептуальной точки зрения обычно используются два типа данных времени и даты, и их удобно различать (вышеуказанные стандарты этого не делают): "физическое время" и "гражданское время".
"Физический" момент времени - это точка в непрерывной универсальной временной шкале, с которой сталкивается физика (конечно, игнорируя относительность). Эта концепция может быть надлежащим образом сохранена в UTC, например (если вы можете игнорировать дополнительные секунды).
"Гражданское" время - это спецификация даты и времени, которая следует гражданским нормам: момент времени здесь полностью определяется набором полей даты и времени (Y,M,D,H,MM,S,FS) плюс TZ (спецификация часового пояса). (на самом деле также "календарь"; но давайте предположим, что мы ограничиваем обсуждение григорианским календарем). Часовой пояс и календарь совместно позволяют (в принципе) отображать из одного представления в другое. Но моменты гражданского и физического времени - это принципиально разные типы величин, и они должны концептуально разделяться и обрабатываться по-разному (аналогия: массивы байтов и символьные строки).
Проблема сбивает с толку, потому что мы говорим об этих типах событий взаимозаменяемо, и потому что гражданские времена подвержены политическим изменениям. Проблема (и необходимость различать эти понятия) становится более очевидной для событий в будущем. Пример (взят из моего обсуждения здесь.
Джон записывает в своем календаре напоминание о каком-то событии в дату и время2019-Jul-27, 10:30:00
TZ=Chile/Santiago
(со смещением GMT-4, следовательно, соответствует UTC 2019-Jul-27 14:30:00
). Но когда-нибудь в будущем страна решит изменить смещение TZ на GMT-5.
Теперь, когда придет день... должно ли это напоминание вызвать
A) 2019-Jul-27 10:30:00 Chile/Santiago
знак равно UTC time 2019-Jul-27 15:30:00
?
или же
B) 2019-Jul-27 9:30:00 Chile/Santiago
знак равно UTC time 2019-Jul-27 14:30:00
?
Нет правильного ответа, если только вы не знаете, что Джон имел в виду, когда говорил календарю "Пожалуйста, позвоните мне 2019-Jul-27, 10:30:00
TZ=Chile/Santiago
".
Он имел в виду "гражданскую дату-время" ("когда часы в моем городе показывают 10:30")? В этом случае А) является правильным ответом.
Или он имел в виду "физический момент времени", точку в непрерывной линии времени нашей вселенной, скажем, "когда произойдет следующее солнечное затмение". В этом случае ответ B) является правильным.
Некоторые API Date / Time правильно понимают это различие: среди них Jodatime, который является основой следующего (третьего!) Java DateTime API (JSR 310).
Проведите четкое архитектурное разделение задач - точно знать, какой уровень взаимодействует с пользователями, и должен изменить дату / время для / из канонического представления (UTC). Дата и время не в формате UTC - это представление (следует за часовым поясом пользователя), время в формате UTC - это модель (остается уникальным для внутреннего и промежуточного уровней)
Кроме того, решите, какова ваша реальная аудитория, что вам не нужно обслуживать и где вы проводите черту. Не трогайте экзотические календари, если у вас нет важных клиентов, а затем подумайте об отдельных серверах, ориентированных на пользователя, только для этого региона.
Если вы можете получить и сохранить местоположение пользователя, используйте местоположение для систематического преобразования даты и времени (скажем,.NET-культура или таблица SQL), но предоставьте конечному пользователю способ выбора переопределений, если дата-время критически важна для ваших пользователей.
Если существуют исторические обязательства по аудиту (например, точно сказать, когда Jo in AZ оплатил счет 2 года назад в сентябре), тогда сохраните для учета как UTC, так и местное время (таблицы конверсии со временем изменятся).
Определите временный часовой пояс для данных, которые поступают в больших объемах, таких как файлы, веб-сервисы и т. Д. Скажем, у компании East Coast есть дата-центр в ЦА - вам нужно спросить и узнать, что они используют в качестве стандарта вместо того, чтобы предполагать одно или другое.
Не доверяйте смещениям часовых поясов, встроенным в текстовое представление даты и времени, и не соглашайтесь анализировать и следовать им. Вместо этого всегда запрашивайте, чтобы часовой пояс и / или эталонный пояс были явно определены. Вы можете легко получить время со смещением PST, но на самом деле это время EST, так как это эталонное время клиента, и записи были просто экспортированы на сервер, который находится в PST.
Вам необходимо знать о базе данных Olson tz, доступной по адресу ftp://elsie.nci.nih.gov/pub http://iana.org/time-zones/. Он обновляется несколько раз в год, чтобы справляться с часто меняющимися в последний момент изменениями того, когда (и нужно ли) переключаться между зимним и летним (стандартным и летним) временем в разных странах мира. В 2009 году последний выпуск был 2009-х годов; в 2010 году это было 2010n; в 2011 году это было 2011n; в конце мая 2012 года был выпущен 2012c. Обратите внимание, что в двух отдельных архивах (tzcode20xxy.tar.gz и tzdata20xxy.tar.gz) есть набор кода для управления данными и самими фактическими данными часового пояса. И код, и данные находятся в свободном доступе.
Это источник названий часовых поясов, таких как America/Los_Angeles (и синонимов, таких как US/Pacific).
Если вам нужно отслеживать различные зоны, вам нужна база данных Olson. Как советуют другие, вы также хотите хранить данные в фиксированном формате - обычно выбирается UTC - вместе с записью часового пояса, в котором были сгенерированы данные. Возможно, вы захотите отличить смещение от времени UTC по времени и имени часового пояса; это может изменить ситуацию позже. Кроме того, зная, что в настоящий момент 2010-03-28T23:47:00-07:00 (США / Тихоокеанский регион) может или не может помочь вам интерпретировать значение 2010-11-15T12:30 - которое предположительно указано в PST (Стандартное тихоокеанское время), а не PDT (Тихоокеанское летнее время).
Стандартные интерфейсы библиотеки C не очень полезны для такого рода вещей.
Данные Olson были перенесены, частично из-за того, что A D Olson скоро уйдет на пенсию, и частично из-за того, что был (теперь отклонен) судебный иск против сопровождающих лиц за нарушение авторских прав. База данных часовых поясов теперь управляется под эгидой IANA, Управления по присвоению номеров в Интернете, и на первой странице есть ссылка на " База данных часовых поясов ". Список рассылки обсуждений теперь tz@iana.org
; список объявлений tz-announce@iana.org
,
Как правило, включайте смещение местного времени (включая смещение летнего времени) в сохраненные временные метки: одного UTC недостаточно, если позднее вы захотите отобразить временную метку в ее исходном часовом поясе (и настройку летнего времени).
Имейте в виду, что смещение не всегда является целым числом часов (например, индийское стандартное время - UTC+05:30).
Например, подходящими форматами являются кортеж (время Unix, смещение в минутах) или ISO 8601.
Пересечение границы "компьютерного времени" и "времени людей" - это кошмар. Основным из них является отсутствие каких-либо стандартов для правил, регулирующих часовые пояса и переход на летнее время. Страны могут в любое время изменить свой часовой пояс и правила перехода на летнее время, и они это делают.
Некоторые страны, например, Израиль, Бразилия, каждый год решают, когда будет переходить на летнее время, поэтому невозможно заранее знать, когда (если) будет действовать ТЛЧ. Другие имеют фиксированные (ish) правила относительно того, когда действует DST. Другие страны не используют DST как все.
Часовые пояса не должны быть полными часовыми отличиями от GMT. Непал +5,45. Есть даже часовые пояса, которые +13. Это означает, что:
SUN 23:00 in Howland Island (-12)
MON 11:00 GMT
TUE 00:00 in Tonga (+13)
все время, но 3 разных дня!
Также нет четкого стандарта на аббревиатуры для часовых поясов и то, как они меняются, когда в DST, так что вы в конечном итоге с такими вещами:
AST Arab Standard Time UTC+03
AST Arabian Standard Time UTC+04
AST Arabic Standard Time UTC+03
Лучший совет - держаться подальше от местного времени, насколько это возможно, и придерживаться UTC, где вы можете. Преобразуйте только в местное время в последний момент.
При тестировании обязательно проверяйте страны в западном и восточном полушариях, причем в настоящее время находится как ТЛЧ, так и нет, и страну, которая не использует ТЛЧ (всего 6).
Для PHP:
Класс DateTimeZone в PHP > 5.2 уже основан на базе данных Olson, которую упоминают другие, поэтому, если вы выполняете преобразование часовых поясов в PHP, а не в базе данных, вы освобождаетесь от работы с (трудными для понимания) файлами Olson.
Однако PHP обновляется не так часто, как БД Olson, поэтому простое использование преобразования часовых поясов в PHP может привести к устаревшей информации о летнем времени и повлиять на правильность ваших данных. Хотя это не ожидается часто, это может произойти, и произойдет, если у вас много пользователей по всему миру.
Чтобы справиться с вышеуказанной проблемой, используйте пакет pecl timezonedb, функция которого заключается в обновлении данных часового пояса PHP. Установите этот пакет так часто, как он обновляется. (Я не уверен, что обновления этих пакетов следуют точно за обновлениями Олсона, но, похоже, они обновляются с частотой, по крайней мере, очень близкой к обновлениям Олсона.)
Если ваш дизайн может вместить его, избегайте преобразования местного времени все вместе!
Я знаю, что для некоторых это может показаться безумным, но подумайте о UX: пользователи обрабатывают близкие относительные даты (сегодня, вчера, следующий понедельник) быстрее, чем абсолютные даты (2010.09.17, пятница, 17 сентября). И когда вы думаете об этом больше, точность часовых поясов (и летнее время) тем важнее, чем ближе дата к now()
, так что если вы можете выразить даты / даты в относительном формате для +/- 1 или 2 недели, остальные даты могут быть в формате UTC, и это не будет иметь большого значения для 95% пользователей.
Таким образом, вы можете хранить все даты в UTC и делать относительные сравнения в UTC и просто отображать пользовательские даты UTC вне вашего порога относительных дат.
Это также может относиться и к пользовательскому вводу (но, как правило, более ограниченным образом). Выбор из выпадающего меню, в котором есть только {Вчера, Сегодня, Завтра, Следующий понедельник, Следующий четверг}, намного проще и проще для пользователя, чем выбор даты. Сборщики даты являются одними из самых вызывающих боль компонентов заполнения формы. Конечно, это не будет работать для всех случаев, но вы можете видеть, что для того, чтобы сделать его очень мощным, требуется лишь немного хитрый дизайн.
Хотя я не пробовал, подход к настройке часового пояса, который я нашел бы убедительным, был бы следующим:
Храните все в UTC.
Создать таблицу
TZOffsets
с тремя столбцами: RegionClassId, StartDateTime и OffsetMinutes (int, в минутах).
В таблице сохраните список дат и времени, когда местное время изменилось, и на сколько. Количество регионов в таблице и число дат будут зависеть от того, какой диапазон дат и областей мира вам нужно поддерживать. Думайте об этом, как будто это "историческая" дата, хотя даты должны включать будущее до некоторого практического предела.
Когда вам нужно вычислить местное время для любого времени UTC, просто сделайте это:
SELECT DATEADD('m', SUM(OffsetMinutes), @inputdatetime) AS LocalDateTime
FROM TZOffsets
WHERE StartDateTime <= @inputdatetime
AND RegionClassId = @RegionClassId;
Возможно, вы захотите кэшировать эту таблицу в своем приложении и использовать LINQ или другие подобные средства для выполнения запросов, а не попадания в базу данных.
Эти данные могут быть извлечены из базы данных общественного достояния tz.
Преимущества и сноски этого подхода:
- В коде нет правил, вы можете легко корректировать смещения для новых регионов или диапазонов дат.
- Вам не нужно поддерживать каждый диапазон дат или регионов, вы можете добавлять их по мере необходимости.
- Регионы не обязательно должны напрямую соответствовать геополитическим границам, и во избежание дублирования строк (например, большинство штатов США обрабатывают DST одинаково), вы можете иметь широкие записи RegionClass, которые в другой таблице связаны с более традиционными списками штаты, страны и т. д.
- В таких ситуациях, как США, где дата начала и окончания летнего времени изменилась за последние несколько лет, с этим довольно легко справиться.
- Поскольку поле StartDateTime также может хранить время, стандартное время переключения 2:00 AM легко обрабатывается.
- Не везде в мире используется 1-часовой DST. Это легко обрабатывает эти случаи.
- Таблица данных является кроссплатформенной и может представлять собой отдельный проект с открытым исходным кодом, который может использоваться разработчиками, которые используют практически любую платформу базы данных или язык программирования.
- Это может быть использовано для смещений, которые не имеют ничего общего с часовыми поясами. Например, 1-секундные корректировки, которые происходят время от времени для корректировки вращения Земли, исторические корректировки внутри и внутри григорианского календаря и т. Д.
- Поскольку это находится в таблице базы данных, стандартные запросы отчетов и т. Д. Могут использовать данные без обхода кода бизнес-логики.
- Это также обрабатывает смещения часового пояса, если вы этого хотите, и может даже учитывать особые исторические случаи, когда регион назначается другому часовому поясу. Все, что вам нужно, это начальная дата, которая назначает смещение часового пояса для каждого региона с минимальной датой начала. Это потребует создания хотя бы одного региона для каждого часового пояса, но позволит вам задать интересные вопросы, такие как: "В чем разница между местным временем между Юмой, штат Аризона, и Сиэтлом, штат Вашингтон, 2 февраля 1989 года в 5:00 утра?" (Просто вычтите одну СУММУ () из другой).
Теперь единственным недостатком этого или любого другого подхода является то, что преобразования из местного времени в GMT не являются совершенными, поскольку любое изменение DST, которое имеет отрицательное смещение по отношению к часам, повторяет данное местное время. Боюсь, нелегкий способ справиться с этим, и это одна из причин, по которой местное время хранится в плохих новостях.
Недавно у меня возникла проблема в веб-приложении, когда при пост-возврате в Ajax дата и время возврата к моему серверному коду отличались от даты и времени.
Скорее всего, это было связано с моим кодом JavaScript на клиенте, который создал дату для отправки обратно клиенту в виде строки, потому что JavaScript корректировал часовой пояс и переход на летнее время, а в некоторых браузерах вычисление времени применения летнего времени казалось, отличается от других.
В итоге я решил полностью удалить вычисления даты и времени на клиенте и отправил обратно на мой сервер по целочисленному ключу, который затем был переведен на дату и время на сервере, чтобы обеспечить согласованные преобразования.
Из этого я узнал: не используйте JavaScript-расчеты даты и времени в веб-приложениях, если это НЕ АБСОЛЮТНО.
Я столкнулся с этим на двух типах систем: "системы планирования смены (например, фабричные рабочие)" и "системы управления газом"...
23 и 25-часовой рабочий день - это боль, с которой приходится справляться, также как и 8-часовые смены, которые занимают 7 или 9 часов. Проблема в том, что вы обнаружите, что у каждого клиента или даже отдела клиента есть свои правила, которые они создали (часто без документирования) в отношении того, что они делают в этих особых случаях.
Некоторые вопросы лучше не задавать клиенту до тех пор, пока они не оплатят ваше "готовое" программное обеспечение. Очень редко можно встретить покупателя, который задумывается об этом типе проблемы при покупке программного обеспечения.
Я думаю, что во всех случаях вы должны записывать время в UTC и конвертировать в / из местного времени перед сохранением даты / времени. Однако даже знать, какое время занимает определенное время, может быть сложно с переходом на летнее и часовые пояса.
Когда речь идет о приложениях, которые запускаются на сервере, включая веб-сайты и другие серверные службы, настройка часового пояса сервера должна игнорироваться приложением.
Общий совет - установить часовой пояс сервера на UTC. Это действительно хорошая передовая практика, но она служит вспомогательным средством для приложений, которые не следуют другим передовым методам. Например, служба может записывать в файлы журнала локальные временные метки, а не временные метки на основе UTC, создавая, таким образом, неоднозначности при переходе на переход на летнее время. Установка часового пояса сервера в UTC исправит это приложение. Однако реальное исправление было бы для приложения, чтобы войти, используя UTC для начала.
Серверный код, включая веб-сайты, никогда не должен ожидать, что местный часовой пояс сервера будет чем-то конкретным.
В некоторых языках местный часовой пояс может легко проникнуть в код приложения. Например, DateTime.ToUniversalTime
метод в.NET будет конвертировать из местного часового пояса в UTC, а DateTime.Now
свойство возвращает текущее время в местном часовом поясе. Так же Date
Конструктор в JavaScript использует локальный часовой пояс компьютера. Есть много других примеров, подобных этому. Важно практиковать защитное программирование, избегая любого кода, который использует настройку локального часового пояса компьютера.
Зарезервируйте с использованием местного часового пояса для клиентского кода, такого как настольные приложения, мобильные приложения и клиентский JavaScript.
Для Интернета правила не так сложны...
- Серверная сторона, используйте UTC
- Клиентская сторона, используйте Olson
- Причина: смещения UTC не являются безопасным переходом на летнее время (например, Нью-Йорк - EST (UTC - 5 часов) часть года, EDT (UTC - 4 часа) - остальная часть года).
- Для определения часового пояса на стороне клиента у вас есть два варианта:
- 1) Пользователь установил зону (безопаснее)
- Ресурсы: веб-готовый Olson tz HTML Dropdown и JSON
- 2) Зона автоопределения
- Ресурс: jsTimezoneDetect
- 1) Пользователь установил зону (безопаснее)
Остальное - просто UTC/ локальное преобразование с использованием ваших серверных библиотек даты и времени. Хорошо пойти...
Установите для своих серверов значение UTC и убедитесь, что все они настроены для ntp или эквивалентного.
UTC позволяет избежать проблем с переходом на летнее время, а несинхронизированные серверы могут привести к непредсказуемым результатам, для диагностики которых требуется некоторое время.
Будьте осторожны при работе с метками времени, хранящимися в файловой системе FAT32 - они всегда сохраняются в локальных координатах времени (включая DST - см. Статью msdn). Сгорел на этом.
Еще одна вещь: убедитесь, что на серверах установлено актуальное исправление перехода на летнее время.
В прошлом году у нас была ситуация, когда наше время постоянно сокращалось на один час в течение трехнедельного периода для пользователей из Северной Америки, хотя мы использовали систему на основе UTC.
Оказывается, в конце концов это были серверы. Им просто нужно было применить современное исправление ( Windows Server 2003).
РНР DateTimeZone::listAbbreviations()
выход
Этот метод PHP возвращает ассоциативный массив, содержащий некоторые "основные" часовые пояса (например, CEST), которые сами по себе содержат более конкретные "географические" часовые пояса (например, Европа / Амстердам).
Если вы используете эти часовые пояса и их смещение / информацию о летнем времени, чрезвычайно важно понимать следующее:
Кажется, что все различные конфигурации смещения /DST (включая исторические конфигурации) каждого часового пояса включены!
Например, Европа / Амстердам можно найти шесть раз в выходных данных этой функции. Два события (смещение 1172/4772) относятся к амстердамскому времени до 1937 года; два (1200/4800) для времени, которое использовалось между 1937 и 1940 годами; и два (3600/4800) для времени, используемого с 1940 года.
Таким образом, вы не можете полагаться на информацию о смещении /DST, возвращаемую этой функцией как правильную в настоящее время / используемую!
Если вы хотите узнать текущее смещение / летнее время определенного часового пояса, вам нужно будет сделать что-то вроде этого:
<?php
$now = new DateTime(null, new DateTimeZone('Europe/Amsterdam'));
echo $now->getOffset();
?>
Деловые правила всегда должны работать в гражданское время (если не существует законодательства, которое гласит иначе). Имейте в виду, что гражданское время - это беспорядок, но это то, что люди используют, поэтому важно.
Внутренне, храните временные метки во что-то вроде гражданского времени-секунд-от-эпохи. Эпоха не имеет особого значения (я предпочитаю эпоху Unix), но она делает вещи проще, чем альтернатива. Представьте, что високосных секунд не существует, если вы не делаете что-то, в чем они действительно нуждаются (например, отслеживание спутника). Отображение между временными метками и отображаемым временем является единственной точкой, где должны применяться правила летнего времени; правила часто меняются (на глобальном уровне, несколько раз в год; обвиняют политиков), поэтому вам следует убедиться, что вы не жестко закодировали отображение. База данных Олсона TZ бесценна.
Если вам случается поддерживать системы баз данных, которые работают с активным DST, тщательно проверьте, нужно ли их отключать во время перехода осенью. Mandy DBS (или другие системы) также не любят дважды проходить одну и ту же точку по (местному) времени, что и происходит, когда вы возвращаете часы назад. SAP решил эту проблему с помощью (ИМХО действительно аккуратного) обходного пути - вместо того, чтобы повернуть время вспять, они просто позволили внутренним часам работать на половине обычной скорости в течение двух часов...
Только один пример, чтобы доказать, что время обработки - это описанный огромный беспорядок, и что вы никогда не будете довольны. В некоторых местах на этой странице дополнительные секунды были проигнорированы.
Несколько лет назад операционная система Android использовала спутники GPS для получения эталона времени UTC, но игнорировала тот факт, что спутники GPS не используют високосные секунды. Никто не заметил, пока в канун Нового года не было путаницы, когда пользователи телефонов Apple и Android-телефонов делали обратный отсчет с интервалом около 15 секунд.
Я думаю, что с тех пор это было исправлено, но вы никогда не знаете, когда эти "мелкие детали" снова будут преследовать вас.
Используете ли вы .NET Framework? Если это так, позвольте мне представить вам тип DateTimeOffset, добавленный в.NET 3.5.
Эта структура содержит как DateTime
и смещение (TimeSpan
), который указывает разницу между DateTimeOffset
дата и время экземпляра и всемирное координированное время (UTC).
DateTimeOffset.Now
статический метод вернетDateTimeOffset
экземпляр, состоящий из текущего (локального) времени и локального смещения (как определено в региональной информации операционной системы).DateTimeOffset.UtcNow
статический метод вернетDateTimeOffset
экземпляр, состоящий из текущего времени в UTC (как если бы вы были в Гринвиче).
Другими полезными типами являются классы TimeZone и TimeZoneInfo.
Для тех, кто борется с этим в .NET, посмотрите, если используете DateTimeOffset
и / или TimeZoneInfo
стоят вашего времени.
Если вы хотите использовать часовые пояса IANA/Olson или считаете, что встроенных типов недостаточно для ваших нужд, обратитесь к Noda Time, которая предлагает гораздо более интеллектуальный API даты и времени для.NET.
Просто хотел указать на две вещи, которые кажутся неточными или, по крайней мере, сбивают с толку:
Всегда сохраняйте время в соответствии с единым стандартом, на который не влияет переход на летнее время. GMT и UTC упоминались разными людьми, хотя UTC упоминается чаще всего.
Для (почти) всех практических вычислительных целей UTC фактически является GMT. Если вы не видите метки времени с долей секунды, вы имеете дело с GMT, что делает это различие избыточным.
Включите местное смещение времени как есть (включая смещение DST) при сохранении временных меток.
Временная метка всегда представлена в GMT и поэтому не имеет смещения.
Вот мой опыт: -
(Не требует сторонней библиотеки)
- На стороне сервера сохраняйте время в формате UTC, чтобы все значения даты / времени в базе данных были в одном стандарте независимо от местоположения пользователей, серверов, часовых поясов или летнего времени.
- На уровне пользовательского интерфейса или в электронных письмах, отправляемых пользователю, вам нужно показывать время в соответствии с пользователем. В связи с этим вам нужно иметь смещение часового пояса пользователя, чтобы вы могли добавить это смещение к значению UTC вашей базы данных, что приведет к локальному времени пользователя. Вы можете либо принять смещение часового пояса пользователя, когда он регистрируется, либо вы можете автоматически определять его на веб-и мобильных платформах. Для веб-сайтов метод JavaScript getTimezoneOffset() является стандартом начиная с версии 1.0 и совместим со всеми браузерами. (Ссылка: http://www.w3schools.com/jsref/jsref_getTimezoneOffset.asp)
Видео Тома Скотта о часовых поясах на YouTube на канале Computerphile также содержит приятное и занимательное описание темы. Примеры включают в себя:
- Самоа (остров в Тихом океане) сместил свой часовой пояс на 24 часа вперед, чтобы упростить торговлю с Австралией и Новой Зеландией,
- Западный берег, где 2 группы людей следуют за разными часовыми поясами,
- 18 век переходит от юлианского календаря к григорианскому календарю (что произошло в 20 веке в России).
На самом деле kernel32.dll не экспортирует SystemTimeToTzSpecificLocation. Однако он экспортирует следующие два: SystemTimeToTzSpecificLocalTime и TzSpecificLocalTimeToSystemTime...
- Никогда, никогда не храните местное время без его смещения UTC (или ссылки на часовой пояс) - примеры того, как этого не делать, включают FAT32 и
struct tm
в C.¹ - Поймите, что часовой пояс представляет собой комбинацию
- набор смещений UTC (например, +0100 зимой, +0200 летом)
- правила, когда происходит переключение (которое может меняться со временем: например, в 1990-х годах ЕС согласовал переключение на последнее воскресенье в марте и октябре в 02:00 по стандартному времени /03:00 по летнему времени; ранее это отличалось между государствами-членами).
¹ Некоторые реализации struct tm
сохраните смещение UTC, но это не вошло в стандарт.
Никогда не полагайтесь только на конструкторов, таких как
new DateTime(int year, int month, int day, int hour, int minute, TimeZone timezone)
Они могут генерировать исключения, когда определенное время даты не существует из-за летнего времени. Вместо этого создайте свои собственные методы для создания таких дат. В них отлавливают любые исключения, возникающие из-за перехода на летнее время, и корректируют время, необходимое с помощью смещения перехода. Летнее время может происходить в разные даты и в разные часы (даже в полночь для Бразилии) в зависимости от часового пояса.
Имея дело с базами данных (в частности, с MySQL, но это относится к большинству баз данных), мне было трудно хранить UTC.
- Базы данных обычно работают с сервером datetime по умолчанию (то есть CURRENT_TIMESTAMP).
- Возможно, вы не сможете изменить часовой пояс сервера.
- Даже если вы можете изменить часовой пояс, у вас может быть сторонний код, который ожидает, что часовой пояс сервера будет локальным.
Я обнаружил, что проще просто хранить дату и время сервера в базе данных, а затем позволить базе данных преобразовывать сохраненную дату и время обратно в UTC (то есть UNIX_TIMESTAMP()) в инструкциях SQL. После этого вы можете использовать дату и время как UTC в своем коде.
Если у вас есть 100% контроль над сервером и всем кодом, вероятно, лучше изменить часовой пояс сервера на UTC.