datetime c# - Лучшее время для летнего времени и часовых поясов




to datetimeoffset (25)

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

Если у вас есть что добавить, пожалуйста, сделайте

Многие системы зависят от сохранения точного времени, проблема связана с изменениями времени из-за перехода на летнее время - перемещение часов вперед или назад.

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

  • Как вы справились с проблемой летнего времени?
  • Какие предположения являются частью вашего решения? (поиск контекста здесь)

Как важно, если не более того:

  • Что вы попробовали, это не сработало?
  • Почему это не сработало?

Я был бы заинтересован в программировании, ОС, сохранении данных и других соответствующих аспектах проблемы.

Общие ответы велики, но я также хотел бы видеть детали, особенно если они доступны только на одной платформе.


Answers

При работе с базами данных (в частности, MySQL , но это касается большинства баз данных), мне было трудно хранить UTC.

  • Базы данных обычно работают с сервером datetime по умолчанию (то есть CURRENT_TIMESTAMP).
  • Возможно, вы не сможете изменить часовой пояс сервера.
  • Даже если вы можете изменить часовой пояс, у вас может быть сторонний код, который ожидает, что часовой пояс сервера будет локальным.

Мне было проще просто хранить дату и время сервера в базе данных, а затем позволить базе данных преобразовать сохраненное datetime в UTC (то есть UNIX_TIMESTAMP ()) в операторы SQL. После этого вы можете использовать datetime как UTC в своем коде.

Если у вас есть 100% контроль над сервером и всем кодом, вероятно, лучше изменить часовой пояс сервера на UTC.


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

Внутренне держите отметки времени в чем-то вроде civil-time-seconds-from-epoch. epoch не имеет значения , в частности , (я предпочитаю эпоху Unix ) , но он делает вещи проще , чем альтернатива. Представьте, что leap-seconds не существуют, если вы не делаете то, что им действительно нужно (например, отслеживание спутников). Отображение между отметками времени и отображаемым временем является единственной точкой, в которой должны применяться правила DST ; правила часто меняются (на глобальном уровне, несколько раз в год, обвиняют политиков), поэтому вы должны быть уверены, что не скопируете картографирование. База данных TZ Олсона неоценима.


На самом деле kernel32.dll не экспортирует SystemTimeToTzSpecificLocation. Однако он экспортирует следующие два: SystemTimeToTzSpecificLocalTime и TzSpecificLocalTimeToSystemTime ...


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

Несколько лет назад операционная система Android использовала спутники GPS для получения информации о времени UTC, но проигнорировала тот факт, что спутники GPS не используют скачки секунд. Никто не заметил, пока не возникла путаница в канун Нового года, когда пользователи телефонов Apple и пользователи телефонов Android сделали свои обратные отсчеты примерно на 15 секунд друг от друга.

Я думаю, что с тех пор он исправлен, но вы никогда не знаете, когда эти «мелкие детали» вернутся, чтобы преследовать вас.


Если вам приходится поддерживать системы баз данных, которые работают с активным DST, внимательно проверьте, нужно ли их отключать во время перехода осенью. Mandy DBS (или другие системы) не любят пропускать одну и ту же точку в (локальном) времени дважды, что точно происходит, когда вы поворачиваете назад осенью. SAP решила это с помощью (IMHO действительно опрятного) решения - вместо того, чтобы возвращать часы, они просто позволяют внутренним часам работать на половине обычной скорости в течение двух часов ...


Никогда не полагайтесь только на таких конструкторов, как

 new DateTime(int year, int month, int day, int hour, int minute, TimeZone timezone)

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


Резюме ответов и других данных: (пожалуйста, добавьте ваши)

Делать:

  • Всякий раз, когда вы ссылаетесь на точный момент времени, сохраняйте время в соответствии с единым стандартом, на который не влияет дневная экономия. (GMT и UTC эквивалентны в этом отношении, но предпочтительно использовать термин UTC. Обратите внимание, что UTC также известен как Zulu или Z time.)
  • Если вместо этого вы решите сохранить время с использованием местного значения времени, включите локальное смещение по времени для данного конкретного времени с UTC (это смещение может меняться в течение года), так что метка времени может быть позже интерпретирована однозначно.
  • В некоторых случаях вам может потребоваться сохранить время UTC и эквивалентное местное время. Часто это делается с двумя отдельными полями, но некоторые платформы поддерживают тип datetimeoffset который может хранить оба в одном поле.
  • При сохранении временных меток в качестве числового значения используйте Unix time - количество целых секунд с 1970-01-01T00:00:00Z (исключая секунды прыжка). Если вам требуется более высокая точность, вместо этого используйте миллисекунды. Это значение всегда должно основываться на UTC без какой-либо регулировки часового пояса.
  • Если позже вам понадобится изменить временную метку, включите исходный идентификатор часового пояса, чтобы определить, может ли смещение быть изменено с записанного исходного значения.
  • При планировании будущих событий обычно предпочитается местное время вместо UTC, так как обычно смещение изменяется. См. Ответ и сообщение в блоге .
  • При сохранении целых дат, таких как дни рождения и юбилеи, не конвертируйте в UTC или в любой другой часовой пояс.
    • Когда это возможно, сохраните в типе данных только для даты, который не включает время суток.
    • Если такой тип недоступен, обязательно обязательно игнорируйте время дня при интерпретации значения. Если вы не можете быть уверены, что время суток будет проигнорировано, выберите 12:00 полдень, а не 00:00 Midnight, как более безопасное представительное время в этот день.
  • Помните, что смещения часовых поясов не всегда являются целым числом часов (например, индийское стандартное время - UTC + 05: 30, а Непал использует UTC + 05: 45).
  • Если вы используете Java, используйте java.time для Java 8 или используйте Joda Time для Java 7 или ниже.
  • Если вы используете .NET , подумайте об использовании Noda Time .
  • Если вы используете .NET без времени Noda, считайте, что DateTimeOffset часто является лучшим выбором, чем DateTime .
  • Если вы используете Perl, используйте DateTime .
  • Если вы используете Python, используйте dateutil или dateutil .
  • Если вы используете JavaScript, используйте moment.js с расширением moment-timezone .
  • Если вы используете PHP> 5.2, используйте преобразования собственных часовых поясов, предоставляемые классами DateTime и DateTimeZone . Будьте осторожны при использовании DateTimeZone::listAbbreviations() - см. Ответ . Чтобы поддерживать PHP в актуальных данных Olson, периодически устанавливайте пакет PECL timezonedb ; см. ответ .
  • Если вы используете C ++, обязательно используйте библиотеку, которая использует правильно реализует базу данных часовых поясов IANA . К ним относятся cctz , ICU и библиотека «tz» Говарда Хиннанта .
    • Не используйте Boost для преобразования часовых поясов. Хотя его API утверждает, что поддерживает стандартные идентификаторы IANA (aka «zoneinfo»), он грубо сопоставляет их с данными в стиле POSIX, не учитывая богатую историю изменений, которые могли иметь каждая зона. (Кроме того, файл вышел из обслуживания.)
  • Если вы используете Rust, используйте chrono .
  • Большинство бизнес-правил используют гражданское время, а не UTC или GMT. Поэтому планируйте преобразование временных меток UTC в локальный часовой пояс перед применением прикладной логики.
  • Помните, что временные зоны и смещения не являются фиксированными и могут меняться. Например, исторически США и Великобритания использовали те же даты, что и «весна вперед» и «отступать». Однако в 2007 году США изменили даты, когда часы меняются. Это означает, что в течение 48 недель в году разница между лондонским временем и временем в Нью-Йорке составляет 5 часов и 4 недели (3 весной, 1 осенью) - 4 часа. Помните о таких элементах при любых вычислениях, которые включают несколько зон.
  • Рассмотрим тип времени (фактическое время события, время трансляции, относительное время, историческое время, повторяющееся время), какие элементы (временная метка, смещение часового пояса и имя часового пояса) необходимо сохранить для правильного поиска - см. «Типы времени» в этот ответ .
  • Храните файлы ОС, базы данных и приложений tzdata в синхронизации, между собой и остальным миром.
  • На серверах установите аппаратные часы и часы ОС на UTC, а не на локальный часовой пояс.
  • Независимо от предыдущей маркерной точки серверный код, включая веб-сайты, никогда не должен ожидать, что локальный часовой пояс сервера будет чем-то конкретным. см. ответ .
  • Предпочитаете работать с часовыми поясами в каждом конкретном случае в коде приложения, а не глобально через настройки файла конфигурации или значения по умолчанию.
  • Используйте службы NTP на всех серверах.
  • Если вы используете FAT32 , помните, что временные метки сохраняются в локальное время, а не в формате UTC.
  • Если вы имеете дело с повторяющимися событиями (например, еженедельным телешоу), помните, что время изменяется с помощью DST и будет отличаться по часовым поясам.
  • Всегда запрашивайте значения даты и времени как включенные в нижнюю границу, исключая верхнюю границу ( >= , < ).

Не рекомендуется :

  • Не путайте «часовой пояс», например America/New_York с «смещением часового пояса», например -05:00 . Это две разные вещи. См. Вики-метку часового пояса .
  • Не используйте JavaScript-объект Date для выполнения вычислений даты и времени в старых веб-браузерах, поскольку ECMAScript 5.1 и ниже имеют дефект дизайна, который может неправильно использовать летнее время. (Это было исправлено в ECMAScript 6/2015).
  • Никогда не доверяйте часам клиента. Возможно, это неверно.
  • Не говорите людям «всегда использовать UTC везде». Этот широко распространенный совет близок к нескольким допустимым сценариям, описанным ранее в этом документе. Вместо этого используйте соответствующую ссылку времени для данных, с которыми работаете. ( Timestamping может использовать UTC, но планирование в будущем времени и значения даты не должны.)

Тестирование:

  • При тестировании убедитесь, что вы тестируете страны в западном, восточном, северном и Southern полушариях (фактически в каждой четверти земного шара, так что в четырех регионах), причем оба летних дня и не (8), и страна, которая делает не использовать DST (еще 4 для охвата всех регионов, всего 12).
  • Тестовый переход DST, т. Е. Когда вы находитесь в летнее время, выберите значение времени зимой.
  • Испытайте пограничные случаи, такие как часовой пояс, который является UTC + 12, с летним временем, делая местное время UTC + 13 летом и даже местами, которые являются UTC + 13 зимой
  • Проверьте все сторонние библиотеки и приложения и убедитесь, что они правильно обрабатывают данные часового пояса.
  • Проверяйте полчаса часовых поясов, по крайней мере.

Ссылка:

Другой:

  • Лобби вашего представителя, чтобы прекратить мерзость, которая является DST. Мы всегда можем надеяться ...
  • Лобби для стандартного времени Земли

Вы должны знать о базе данных 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 (US / Pacific) может или не поможет вам интерпретировать значение 2010-11-15T12: 30 - которое предположительно указано в PST ( Тихоокеанское стандартное время), а не PDT (тихоокеанское летнее время).

Стандартные библиотеки C-библиотек не очень полезны для такого рода вещей.

Данные Олсона переместились, отчасти потому, что AD Olson скоро уйдет в отставку, а отчасти из-за того, что был подан иск (в настоящее время уволен) против сопровождающих за нарушение авторских прав. База данных часовых поясов теперь управляется под эгидой IANA , авторитета Internet Assigned Numbers, а на первой странице есть ссылка на « База данных IANA » . Список рассылки для обсуждения - [email protected] ; список объявлений - [email protected] .


Хотя я и не пробовал, подход к настройкам часовых поясов, которые я бы нашел убедительными, был бы следующим:

  1. Сохраняйте все в UTC.

  2. Создайте таблицу TZOffsets с тремя столбцами: RegionClassId, StartDateTime и OffsetMinutes (int, в минутах).

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

Когда вам нужно вычислить местное время любого времени UTC, просто выполните следующее:

SELECT DATEADD('m', SUM(OffsetMinutes), @inputdatetime) AS LocalDateTime
FROM   TZOffsets
WHERE  StartDateTime <= @inputdatetime
       AND RegionClassId = @RegionClassId;

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

Эти данные могут быть удалены из базы данных tz общественного домена .

Преимущества и сноски этого подхода:

  1. В коде нет правил, вы можете легко настроить смещения для новых регионов или диапазонов дат.
  2. Вам не нужно поддерживать каждый диапазон дат или регионов, вы можете добавить их по мере необходимости.
  3. Регионы не должны напрямую соответствовать геополитическим границам и избегать дублирования строк (например, большинство государств в США обрабатывают DST одинаково), вы можете иметь обширные записи RegionClass, которые ссылаются в другой таблице на более традиционные списки государства, страны и т. д.
  4. В таких ситуациях, как США, где начальная и конечная дата DST изменилась за последние несколько лет, с этим довольно легко справиться.
  5. Так как поле StartDateTime также может хранить время, стандартное время переключения 2:00 AM обрабатывается легко.
  6. Не везде в мире используется 1-часовой ДСТ. Это легко справляется с этими случаями.
  7. Таблица данных является кросс-платформенной и может быть отдельным проектом с открытым исходным кодом, который может использоваться разработчиками, которые используют практически любую платформу базы данных или язык программирования.
  8. Это можно использовать для смещений, которые не имеют никакого отношения к часовым поясам. Например, 1-секундные корректировки, которые время от времени могут корректироваться для вращения Земли, исторические корректировки и внутри григорианского календаря и т. Д.
  9. Поскольку это находится в таблице базы данных, стандартные запросы отчетов и т. Д. Могут использовать данные без отключения кода бизнес-логики.
  10. Это также относится к смещениям часовых поясов, если вы этого хотите, и может даже учитывать особые исторические случаи, когда регион назначается другому часовому поясу. Все, что вам нужно, это начальная дата, которая присваивает часовой пояс для каждого региона с минимальной датой начала. Это потребует создания по крайней мере одного региона для каждого часового пояса, но позволит задать интересующие вас вопросы: «Какая разница в местном времени между Юмой, Аризоной и Сиэтлом, Вашингтон, 2 февраля 1989 года в 5:00?» (Просто вычтите один SUM () из другого).

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


DateTimeZone::listAbbreviations()Выход PHP

Этот метод PHP возвращает ассоциативный массив, содержащий некоторые «основные» часовые пояса (например, CEST), которые сами по себе содержат более конкретные «географические» часовые пояса (например, Европа / Амстердам).

Если вы используете эти часовые пояса и их информацию о смещении / DST, чрезвычайно важно реализовать следующее:

Кажется, что все разные конфигурации смещения / DST (включая исторические конфигурации) каждого часового пояса включены!

Например, Европа / Амстердам можно найти шесть раз в выходе этой функции. Два события (смещение 1172/4772) относятся к Амстердамскому времени, использованному до 1937 года; два (1200/4800) относятся к тому времени, которое использовалось между 1937 и 1940 годами; и два (3600/4800) относятся к времени, используемому с 1940 года.

Поэтому вы не можете полагаться на информацию о смещении / DST, возвращаемую этой функцией, в качестве правильной / используемой в настоящее время!

Если вы хотите узнать текущее смещение / DST определенного часового пояса, вам нужно будет сделать что-то вроде этого:

<?php
$now = new DateTime(null, new DateTimeZone('Europe/Amsterdam'));
echo $now->getOffset();
?>

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

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

Серверный код, включая веб-сайты, никогда не должен ожидать, что местный часовой пояс сервера будет чем-то конкретным.

На некоторых языках локальный часовой пояс может легко проникать в код приложения. Например, DateTime.ToUniversalTimeметод в .NET будет конвертировать из локального часового пояса в UTC, а DateTime.Nowсвойство возвращает текущее время в локальном часовом поясе. Кроме того, Dateконструктор в JavaScript использует локальный часовой пояс компьютера. Есть много других подобных примеров. Важно практиковать защитное программирование, избегая любого кода, который использует локальный часовой пояс компьютера.

Зарезервируйте, используя локальный часовой пояс для клиентского кода, например настольные приложения, мобильные приложения и клиентский JavaScript.


Тома Скотта видео о часовых поясах на YouTube на канале Computerphile также имеет приятное и интересное описание темы. Примеры включают:

  • Самоа (остров в Тихом океане) переводит свой часовой пояс вперед на 24 часа, чтобы облегчить торговлю с Австралией и Новой Зеландией,
  • Западный берег , где 2 популяции людей следуют за часовыми поясами,
  • XVIII век меняется от юлианского календаря до григорианского календаря (который произошел в XX веке в России).

Вот мой опыт: -

(Не требуется сторонняя библиотека)

  • На стороне сервера сохраняйте время в формате UTC, чтобы все значения даты / времени в базе данных находились в одном стандарте независимо от местоположения пользователей, серверов, часовых поясов или DST.
  • На уровне пользовательского интерфейса или в сообщениях электронной почты, отправленных пользователю, вам нужно показать время в соответствии с пользователем. В этом случае вам необходимо иметь смещение часового пояса пользователя, чтобы вы могли добавить это смещение в значение UTC базы данных, которое приведет к локальному времени пользователя. Вы можете либо принять смещение часового пояса пользователя при их регистрации, либо автоматически обнаружить их на веб-и мобильных платформах. Для веб-сайтов функция JavaScript getTimezoneOffset () является стандартной версией версии 1.0 и совместима со всеми браузерами. (Ссылка: http://www.w3schools.com/jsref/jsref_getTimezoneOffset.asp )

Используете ли вы платформу .NET ? Если да, позвольте мне представить вам тип DateTimeOffset , добавленный с .NET 3.5.

Эта структура содержит как a, так DateTimeи Offset ( TimeSpan), которая определяет разницу между DateTimeOffsetдатой и временем экземпляра и временем согласованного универсального времени (UTC).

  • DateTimeOffset.NowСтатический метод возвращает DateTimeOffsetэкземпляр , состоящий из текущего (локального) времени, а местное смещение (как определено в региональной информации операционной системы).

  • DateTimeOffset.UtcNowСтатический метод возвращает DateTimeOffsetэкземпляр , состоящий из текущего времени в UTC (как если бы вы были в Гринвиче).

Другими полезными типами являются классы TimeZone и TimeZoneInfo .


Я ударил это по двум типам систем: «системы планирования сдвига (например, заводские рабочие») и «системы управления газом» ...

23 и 25-часовые длинные дни - это боль, с которой можно справиться, так что это 8-часовой сдвиг, который занимает 7 часов или 9 часов. Проблема заключается в том, что вы обнаружите, что у каждого клиента или даже отдела клиента есть разные правила, которые они создали (часто без документирования) на то, что они делают в этих особых случаях.

Некоторые вопросы лучше не запрашивать у клиента до тех пор, пока они не оплатят программное обеспечение «с полки». Очень редко можно найти клиента, который думает об этом типе проблемы перед покупкой программного обеспечения.

Я думаю, что во всех случаях вам нужно записывать время в UTC и конвертировать в / из местного времени, прежде чем хранить дату / время. Однако даже знать, которые принимают заданное время, может быть сложно с летнего времени и часовых поясов.


Если ваш дизайн может вместить его, избегайте локального преобразования времени!

Я знаю, что это может показаться сумасшедшим, но подумайте о UX: пользователи начинают приближаться, относительные даты (сегодня, вчера, в следующий понедельник) быстрее, чем абсолютные даты (2010.09.17, пятница 17 сентября). И когда вы думаете об этом больше, точность часовых поясов (и DST) важнее, чем ближе дата к now() , поэтому, если вы можете выразить даты / даты в относительном формате для +/- 1 или 2 недель, остальные даты могут быть UTC, и это не слишком важно для 95% пользователей.

Таким образом, вы можете хранить все даты в UTC и выполнять относительные сравнения в UTC и просто показывать даты UTC пользователя за пределами своего порога относительной даты.

Это также может относиться и к пользовательскому вводу (но обычно более ограниченным образом). Выбор из раскрывающегося списка, который имеет только {Вчера, сегодня, завтра, в следующий понедельник, следующий четверг), намного проще и проще для пользователя, чем выбор даты. Сборщики даты являются одними из наиболее болевых компонентов, заполняющих форму. Конечно, это не сработает для всех случаев, но вы можете видеть, что для этого он требует очень умного дизайна.


Держите серверы в UTC и убедитесь, что все они настроены для ntp или эквивалента.

UTC избегает проблем с летним временем, а серверы вне синхронизации могут вызывать непредсказуемые результаты, которые требуют времени для диагностики.


Для PHP:

Класс DateTimeZone в PHP> 5.2 уже основан на Olson DB, о котором говорят другие, поэтому, если вы делаете преобразования часовых поясов в PHP, а не в БД, вы освобождаетесь от работы с (труднодоступными) файлами Olson.

Тем не менее, PHP не обновляется так часто, как Olson DB, поэтому просто использование PHP-часовых поясов может оставить вам устаревшую информацию о DST и повлиять на правильность ваших данных. Хотя этого не ожидается часто, это может произойти, и это произойдет, если у вас будет большая база пользователей по всему миру.

Чтобы справиться с вышеуказанной проблемой, используйте пакет timezonedb pecl , это функция обновления данных часового пояса PHP. Установите этот пакет так часто, как он обновляется. (Я не уверен, что обновления этого пакета следуют за обновлениями Olson точно, но, похоже, они обновляются на частоте, которая, по крайней мере, очень близка к обновлениям Olson.)


У меня недавно возникла проблема в веб-приложении, где на Ajax после обратной связи datetime, возвращающийся к моему серверному коду, отличался от времени, которое было выполнено.

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

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

Я учился на этом: не используйте расчеты даты и времени JavaScript в веб-приложениях, если только вы НЕОБХОДИМО выполнить.


Сделать четкое архитектурное разделение проблем - точно знать, с каким ярусом взаимодействует с пользователями, и изменять дату-время для / из канонического представления (UTC). Не-UTC дата-время - презентация (следующая локальная часовая зона пользователей), время UTC - модель (остается уникальной для внутренних и средних уровней).

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

Если вы можете приобретать и поддерживать местоположение пользователя, используйте место для систематического преобразования даты и времени (например, .NET-культура или SQL-таблица), но предоставляйте возможность конечным пользователям выбирать переопределения, если для ваших пользователей важна дата-время.

Если есть исторические обязательства по аудиту (например, точно сказать, когда Jo в AZ заплатил счет 2 года назад в сентябре), то сохраняйте как UTC, так и местное время для записи (ваши таблицы преобразования будут меняться с течением времени).

Определите временную референтную часовую зону для данных, поступающих в массивные файлы, веб-сервисы и т. Д. У компании East Coast есть центр обработки данных в CA - вам нужно спросить и узнать, что они используют в качестве стандарта, вместо того, чтобы предполагать тот или иной.

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


В общем, включите местное смещение по времени (включая смещение DST) в сохраненные временные метки: только UTC недостаточно, если позже вы захотите отобразить временную метку в своем исходном часовом поясе (и настройке DST).

Имейте в виду, что смещение не всегда является целым числом часов (например, индийское стандартное время - UTC + 05: 30).

Например, подходящими форматами являются кортеж (время unix, смещение в минутах) или ISO 8601 .


Для тех, кто борется с этим на .NET , посмотрите, используете ли вы DateTimeOffsetи / или TimeZoneInfoстоите.

Если вы хотите использовать часовые пояса IANA / Olson или найти встроенные типы недостаточно для ваших нужд, ознакомьтесь с Noda Time , которая предлагает гораздо более умный API для даты и времени для .NET.


Еще одна вещь, убедитесь, что на серверах установлен обновленный патч.

У нас была ситуация в прошлом году, когда наши времена неизменно выходили на один час в течение трех недель для североамериканских пользователей, хотя мы использовали систему, основанную на UTC.

Оказывается, в итоге это были серверы. Им просто потребовался обновленный патч ( Windows Server 2003 ).


Я не уверен, что я могу добавить к ответам выше, но вот несколько моментов от меня:

Типы времени

Есть четыре разных раза, которые вы должны учитывать:

  1. Время события: например, время, когда происходит международное спортивное событие, или коронация / смерть / и т. Д. Это зависит от часового пояса события, а не от зрителя.
  2. Телевизионное время: например, конкретное телешоу транслируется в 9 вечера по местному времени по всему миру. Важно, когда вы думаете о публикации результатов (например, American Idol) на своем веб-сайте
  3. Относительное время: например: у этого вопроса открыта открытая щедрость за 21 час. Это легко отобразить
  4. Повторяющееся время: например: ТВ-шоу проводится каждый понедельник в 9 вечера, даже когда меняется летнее время.

Существует также историческое / альтернативное время. Это раздражает, потому что они не могут вернуться к стандартному времени. Например: юлианские даты, даты в соответствии с лунным календарем на Сатурне, календарь Клингонов.

Хранение времени начала / окончания в UTC работает хорошо. Для 1 вам потребуется имя часового пояса + смещение, сохраненное вместе с событием. Для 2 вам нужен локальный идентификатор времени, хранящийся в каждом регионе, и локальное имя часового пояса + смещение, хранящееся для каждого зрителя (это можно получить из IP-адреса, если вы находитесь в хрусте). Для 3, сохранить в UTC секунд и нет необходимости в часовых поясах. 4 - частный случай 1 или 2 в зависимости от того, является ли это глобальным или локальным событием, но вам также необходимо сохранить созданную по метке времени, чтобы вы могли определить, изменилось ли определение часового пояса до или после создания этого события. Это необходимо, если вам нужно показать исторические данные.

Время хранения

  • Всегда сохраняйте время в UTC
  • Преобразование в локальное время на дисплее (локальный определяется пользователем, просматривающим данные)
  • При хранении часового пояса вам нужно имя, отметка времени и смещение. Это необходимо, потому что правительства иногда меняют значения своих часовых поясов (например: правительство США изменило даты DST), и ваше приложение должно обрабатывать вещи изящно ... например: точная метка времени, когда эпизоды LOST показывали как до, так и после правил DST изменилось.

Смещения и имена

Примером приведенного выше является:

11 июля 2010 года в 19:00 по тихоокеанскому времени в Южной Африке (UTC + 2 - SAST) состоялся финальный матч чемпионата мира по футболу.

С помощью этой информации мы можем исторически определить точное время, когда состоялись финалы WCS 2010 года, даже если определение южноафриканского часового пояса изменилось и сможет отображать это для зрителей в их локальном часовом поясе в момент запроса базы данных.

Системное время

Вам также необходимо синхронизировать файлы операционной системы, базы данных и приложений tzdata, как друг с другом, так и с остальным миром, и тщательно тестировать при обновлении. Не неслыханно, что стороннее приложение, от которого вы зависите, неправильно обрабатывало изменения TZ.

Убедитесь, что аппаратные часы установлены на UTC, и если вы используете серверы по всему миру, убедитесь, что их ОС настроены на использование UTC. Это становится очевидным, когда вам нужно копировать почасовые файлы файлов apache с серверов в несколько часовых поясов. Сортировка их по имени файла работает только в том случае, если все файлы названы с тем же часовым поясом. Это также означает, что вам не нужно делать математику с датой в голове, когда вы ssh из одной коробки в другую, и вам нужно сравнить временные метки.

Кроме того, запустите ntpd на всех ящиках.

клиенты

Никогда не доверяйте метке времени, которую вы получаете с клиентской машины, как действительный. Например, заголовки Date: HTTP или javascript Date.getTime() . Они хороши при использовании в качестве непрозрачных идентификаторов или при выполнении математики даты в течение одного сеанса на одном и том же клиенте, но не пытайтесь перекрестно ссылаться на эти значения на то, что у вас есть на сервере. Ваши клиенты не запускают NTP и могут не иметь рабочий аккумулятор для своих часов BIOS.

пустяки

Наконец, правительства иногда делают очень странные вещи:

Стандартное время в Нидерландах составляло ровно 19 минут и 32,13 секунды до UTC по закону с 1909-05-01 по 1937-06-30. Этот часовой пояс не может быть представлен точно с использованием формата HH: MM.

Хорошо, я думаю, что все готово.


Как объяснили другие, там есть разрыв времени. Есть два возможных смещения 1927-12-31 23:54:08 для 1927-12-31 23:54:08 в Asia/Shanghai , но только одно смещение за 1927-12-31 23:54:07 . Таким образом, в зависимости от того, какое смещение используется, есть либо разница в одну секунду, либо разница в 5 минут и 53 секунды.

Это небольшое смещение смещений вместо обычной одночасовой дневной сбережения (летнее время), к которой мы привыкли, немного затушевывает проблему.

Обратите внимание, что обновление базы данных часовых поясов 2013 года перенесло этот разрыв на несколько секунд раньше, но эффект все равно будет наблюдаться.

Новый пакет java.time на Java 8 позволяет использовать это более четко и предоставлять инструменты для его обработки. Дано:

DateTimeFormatterBuilder dtfb = new DateTimeFormatterBuilder();
dtfb.append(DateTimeFormatter.ISO_LOCAL_DATE);
dtfb.appendLiteral(' ');
dtfb.append(DateTimeFormatter.ISO_LOCAL_TIME);
DateTimeFormatter dtf = dtfb.toFormatter();
ZoneId shanghai = ZoneId.of("Asia/Shanghai");

String str3 = "1927-12-31 23:54:07";  
String str4 = "1927-12-31 23:54:08";  

ZonedDateTime zdt3 = LocalDateTime.parse(str3, dtf).atZone(shanghai);
ZonedDateTime zdt4 = LocalDateTime.parse(str4, dtf).atZone(shanghai);

Duration durationAtEarlierOffset = Duration.between(zdt3.withEarlierOffsetAtOverlap(), zdt4.withEarlierOffsetAtOverlap());

Duration durationAtLaterOffset = Duration.between(zdt3.withLaterOffsetAtOverlap(), zdt4.withLaterOffsetAtOverlap());

Тогда durationAtEarlierOffset будет составлять одну секунду, а durationAtLaterOffset - пять минут и 53 секунды.

Кроме того, эти два смещения одинаковы:

// Both have offsets +08:05:52
ZoneOffset zo3Earlier = zdt3.withEarlierOffsetAtOverlap().getOffset();
ZoneOffset zo3Later = zdt3.withLaterOffsetAtOverlap().getOffset();

Но эти две разные:

// +08:05:52
ZoneOffset zo4Earlier = zdt4.withEarlierOffsetAtOverlap().getOffset();

// +08:00
ZoneOffset zo4Later = zdt4.withLaterOffsetAtOverlap().getOffset();

Вы можете видеть ту же проблему, сравнивая 1927-12-31 23:59:59 с 1928-01-01 00:00:00 , хотя в этом случае это более раннее смещение, которое приводит к более длительной дивергенции, и это более ранняя дата, которая имеет два возможных смещения.

Другой способ приблизиться к этому - проверить, происходит ли переход. Мы можем сделать это вот так:

// Null
ZoneOffsetTransition zot3 = shanghai.getRules().getTransition(ld3.toLocalDateTime);

// An overlap transition
ZoneOffsetTransition zot4 = shanghai.getRules().getTransition(ld3.toLocalDateTime);

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

Надеюсь, это поможет людям справиться с такой проблемой, как только Java 8 станет широко доступным, или тем, кто использует Java 7, которые используют backport JSR 310.





datetime timezone utc dst datetimeoffset