Лучшая практика для хранения DateTime на основе TimeZone

16

Разработка веб-приложения, которое должно позволять пользователю планировать встречу на основе своего часового пояса. И я сохраняю запланированное пользователем время и дату как серверное время в поле базы данных. При отображении расписания информация извлекает значение из базы данных и преобразует в пользовательский тимзон. Обработка в базе кода Я конвертирую DateTime на основе часового пояса пользователя. Пожалуйста, предложите, это лучшая практика или какой-либо простой способ существует?

user46506
источник

Ответы:

33

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

Реально, временные метки должны храниться в фиксированном единственном представлении независимо от того, как они будут интерпретироваться, потому что как бы вы ни старались, у вас всегда будут неоднозначные случаи, и вы не сможете разрешить их без фиксированного представления. И вы выбрали один из худших вариантов использования - планирование встречи. Единственный наиболее распространенный вариант использования - это авиаперелет, когда поездка может начинаться в одном часовом поясе и заканчиваться в другом, возможно в более раннее местное время.

Всегда, всегда ВСЕГДА сохраняйте в UTC и отображайте в предпочтительном или явно указанном часовом поясе пользователя. Если это вообще возможно, заставьте пользователя сообщать вам, в каком часовом поясе, по его мнению, находится временная метка при вводе ( например , иметь явное поле часового пояса и предварительно заполнить его предпочитаемой зоной).

Росс Паттерсон
источник
1
+1. И его гибкий. Наличие общего, согласованного, универсального стандартного эталонного времени - любая разыменование локальной зоны будет выполнено правильно.
радаробоб
На самом деле, планирование встречи является одним из немногих случаев, когда вы не можете сохранить его как UTC: Если правила DST изменятся (или смещение от UTC), что произойдет со временем встречи? В большинстве случаев вы хотите, чтобы время встречи оставалось неизменным локально, что означает изменение значения UTC. Скорее всего, вы захотите сохранить значение, представляющее «TimeInTimeZone + TimeZone», из которого вы могли бы легко получить UTC. В расписании между часовыми поясами (например, в авиакомпаниях) есть ограничения, которые, вероятно, означают, что оба они привыкнут.
Заводная муза
1
О, это становится хуже, чем это. Я регулярно встречаюсь с коллегами из других стран, чьи правила смены времени отличаются от моих. Когда это произойдет, каков правильный ответ? На самом деле, ни один компьютер не может знать :-(
Росс Паттерсон
3

Самый простой способ работы с информацией о дате / времени зависит от требований вашего приложения.

Если дата и время вводятся пользователем, а сервер не обрабатывает эту информацию о дате / времени, кроме как для ее сохранения в базе данных, и не ожидается, что введенное время будет адаптировано к месту, где оно просматривается (например, , пользователь ввел «8:00 PM», и он должен отображаться как «8:00 PM» независимо от того, где в мире он просматривается), тогда самый простой способ - сохранить DateTime как местное время без какой-либо информации о часовом поясе.

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

Барт ван Инген Шенау
источник
-1 для «хранить в местном времени», +1 для «хранить в UTC».
Росс Паттерсон
@RossPatterson: Можете ли вы объяснить «-1» для «хранить по местному времени»? Мне любопытно, почему это должно быть плохой идеей, учитывая условия, которые я дал с этим.
Барт ван Инген Шенау
1
Например, использование локального времени пользователя означает, что каждое значение фактически является одним из нескольких десятков различных типов данных. Это означает, что вам неинтересно выполнять над ними операции базы данных, такие как «TIMESTAMP> '2013-08-27T12: 00: 00'». Это даже означает, что вы не можете знать, когда и если применять переход на летнее время.
Росс Паттерсон
@RossPatterson: Спасибо. Я согласен, что местное время не является правильным решением в большинстве случаев.
Барт ван Инген Шенау
2

Важно, чтобы вы не связывали два взаимосвязанных понятия.

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

Другая концепция - это выражение времени, такое как «8:00 вечера каждый вторник». Вы упомянули, что людям разрешено назначать встречи, и если у вас есть повторяющиеся встречи, вам нужно такое выражение. Я не знаю ни одного стандартного языка выражений, но что бы вы ни использовали, он будет зависеть от часового пояса человека, который его указал. Было бы лучше сделать это прямо, например, «8:00 вечера каждый вторник в тихоокеанском часовом поясе». В случае выражения времени вы всегда сохраняете это как строку и никогда не используете форматы системного времени.

Смотрите больше обсуждений этого в моем блоге

AgilePro
источник
1

Многие ответы здесь указывают на хранение как UTC. Но будь очень осторожен с этим. Например, если вы запланируете встречу на 12:00, но встреча состоится после перехода на летнее время, что произойдет? UTC не хранит никакой информации о том, была ли функция dst активной во время сохранения встречи. Многие крупные известные системы допустили эту ошибку, когда пользователь отправляет электронное письмо летом в 9:00, а зимой отправленное время показывает 8:00, потому что вычисление обратно из UTC зависит от того, когда вы посмотрите на дату и время, не в тот момент, когда дата была записана.

Гораздо лучше предположить, что ваш пользователь хочет иметь время, которое он выбрал всегда. Без преобразования UTC, без преобразования времени, без информации о часовом поясе, ничего. Назначить встречу с 08:00 до 12:00 21 марта 2016 года - это как раз то, что нужно. Не используйте ни местное время, ни время UTC, но укажите неопределенное время (в json это не имеет ни z, ни +, в основном, в .NET это DateTime.Kind = DateTimeKind.Unspecified).

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

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

К счастью, именно здесь приходят такие библиотеки, как http://nodatime.org/, и мы настоятельно рекомендуем это сделать. Они работают с датами гораздо более последовательно. Даже тогда я бы порекомендовал обернуть все ваши переменные даты и логику в ваши собственные обертки, используя интерфейсы, чтобы их можно было смоделировать, и тогда вы все равно сможете переключать логику позже.

Arwin
источник
Я не совсем согласен с вашими выводами, но встреча в полдень, запланированная на переход на летнее время, представляет собой особую проблему, как и еженедельная встреча в полдень, забронированная через несколько лет в будущем.
согнут
« Конечно, если ваш вариант использования заключается в том, что вы являетесь компанией, которая проводит встречи с кем-то из разных часовых поясов, и вы хотите видеть эту информацию, например, в календаре компании, но позволяете пользователям видеть, какое время находится в их часовом поясе, это становится все более сложным. "- это почти каждая компания. Очень немногие компании за пределами Китая и Индии могут игнорировать назначения между часовыми поясами.
Росс Паттерсон
« Таким образом, вы всегда можете рассчитать обратное местное время к чему-либо еще, либо к тому, что было бы сейчас, либо к тому, что было задумано исторически. Поскольку часовые пояса очень не статичны, что еще более усложняет ситуацию ». вы принимаете, что собираетесь делать расчеты, вам действительно нужно выбрать одно представление для времени. UTC, EST (но не EST5EDT), IST, что угодно. Но вы просто не можете иметь значения, основанные на нескольких часовых поясах в одном поле, и выполнять на них какую-либо законную агрегированную обработку. Обработка отображения, конечно. Но это самая легкая часть.
Росс Паттерсон
По крайней мере, вы все еще можете, правильно, конвертировать в UTC. Вы всегда можете создать таблицу расчета или значение из этой информации в ретроспективе. Но вы никогда не сможете пойти другим путем. Обратите внимание, что SQL 2016 начинает поддерживать это изначально, хотя, к сожалению, он все еще опирается - по крайней мере исторически - на не совсем корректные данные реестра - но это еще одно улучшение.
Арвин