Хранение DateTime (UTC) и хранение DateTimeOffset

96

Обычно у меня есть «перехватчик», который прямо перед чтением / записью из / в базу данных выполняет преобразование DateTime (из UTC в местное время и из местного времени в UTC), поэтому я могу использовать DateTime.Now(производные и сравнения) во всей системе, не беспокоясь о часовых поясах.

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

Следует ли мне продолжать хранить свои даты (SQL 2008 - datetime) в формате UTC или вместо этого следует хранить их, используя DateTimeOffset(SQL 2008 - datetimeoffset)?

UTC Даты в базе данных (тип datetime) работают и известны так давно, зачем их менять? Каковы преимущества?

Я уже посмотрел в статьях , как этот , но я не 100% убежден , хотя. есть идеи?

Фредерико
источник
Связанный вопрос: stackoverflow.com/questions/2532729/…
Oded
1
См. Также: DateTime vs DateTimeOffset - написано для .Net, но концептуально применимо и к SQL.
Мэтт Джонсон-Пинт

Ответы:

131

Есть одна огромная разница: вы не можете использовать только UTC.

  • Если у вас есть такой сценарий

    • Один сервер и несколько клиентов (все географически в разных часовых поясах )
    • Клиенты создают некоторые данные с информацией о дате и времени
    • Клиенты хранят все на центральном сервере
  • Затем:

    • datetimeoffset хранит местное время клиента и ТАКЖЕ смещение относительно времени UTC
    • все клиенты знают время всех данных в формате UTC, а также местное время в месте происхождения информации
  • Но:

    • Дата и время в формате UTC хранит только дату и время в формате UTC , поэтому у вас нет информации о местном времени в том месте, где были созданы данные.
    • Другие клиенты не знают местного времени места, откуда пришла информация о дате и времени.
    • Другие клиенты могут рассчитывать только свое местное время из базы данных (используя время в формате UTC), а не местное время клиента, откуда исходят данные.

Простой пример - система бронирования авиабилетов ... Билет должен содержать 2 раза: - время «взлета» (в часовом поясе города «Из») - время «посадки» (в часовом поясе города «Пункт назначения»).

Марсель Тот
источник
2
Это лучшее объяснение, о котором я читал, когда это было бы уместно, и я много читал. Для нас это не кажется таковым. Мы получаем время в формате UTC для наших внешних данных, и мы знаем местоположение из другого источника, если это необходимо (а его никогда не было). Спасибо, что сделали это таким очевидным.
Эндрю Бэкер
19
вы сказали, что "datetimeoffset хранит время в формате UTC и ТАКЖЕ смещение относительно местного времени клиента", но datetimeoffset хранит ЛОКАЛЬНОЕ время + смещение или время UTC + смещение, равное +0.
Сергей Кислый 07
хотя вы можете просто преобразовать DTO в DT, поскольку базой DT является UTC (хотя это будет дополнительным шагом для всех, кто использует базу данных, и, возможно, не проще, чем просто использовать только время UTC)
iliketocode
2
Похоже, DateTmeOffset хранит «Местное время и смещение UTC», а не «Время UTC и смещение UTC». Если вы приведете к datetime или используете любую из функций datepart, вы получите локальные компоненты даты и времени.
Трийнко
« все клиенты знают время в формате UTC для всех данных, а также местное время в месте происхождения информации» Хотя в этом случае сохранение как часть поля даты кажется ненормализованным. Каков вариант использования - то есть почему бы вам не использовать UTC и вытащить смещение до InputLocationId(или аналогичного нормализованного объекта). Здесь будут задействованы вычисления (привет, исключения ... особенно вы, Индиана ), но это все еще детерминированный процесс - и тогда баланс логики даты и времени приложения прост.
ruffin
23

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

Когда использовать местное время? Ответьте на этот вопрос:

Если правительство вдруг решит перейти на летнее время, хотите ли вы, чтобы эти данные изменились вместе с ним?

Сохраняйте местное время, только если ответ «да». Очевидно, это будет только для будущих свиданий, и обычно только для свиданий, которые так или иначе влияют на людей.

Зачем хранить часовой пояс / смещение?

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

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

Бен
источник
4
Преобразование Windows UTC в местное время учитывает переход на летнее время для исторических дат. Я не понимаю, зачем в таком случае хранить местное время.
jamiegs
1
@Jamiegs Windows исторически знает только «последнюю историческую информацию» (как указано / указано в документации .NET DateTime). Он не является исчерпывающим.
2
конечно, вы также должны сохранить место события, иначе вы не можете сказать, в какое «местное время» произошло событие.
keuleJ 06
20

DATETIMEOFFSET дает вам возможность хранить местное время и время UTC в одном поле.

Это позволяет создавать очень простые и эффективные отчеты по местному времени или по всемирному координированному времени без необходимости каким-либо образом обрабатывать данные для отображения.

Это два наиболее распространенных требования - местное время для локальных отчетов и время UTC для групповых отчетов.

Местное время хранится в части DATETIME DATETIMEOFFSET, а OFFSET из UTC хранится в части OFFSET, поэтому преобразование выполняется просто и, поскольку оно не требует знания часового пояса, из которого были получены данные, все может быть выполнено на уровне базы данных. .

Если вам не требуется время до миллисекунд, например, до минут или секунд, вы можете использовать DATETIMEOFFSET (0). В этом случае для поля DATETIMEOFFSET потребуется только 8 байтов памяти - то же самое, что и для DATETIME.

Таким образом, использование DATETIMEOFFSET вместо UTC DATETIME обеспечивает большую гибкость, эффективность и простоту отчетности.

PapillonUK
источник
Слишком плохая структура сущности не имеет никакого способа получить доступ к локальному datetime поля datetimeoffset, что делает невозможным запрос конкретной локальной даты.
Трийнко
@Triynko, ты можешь объяснить, что ты имеешь в виду? Пример?
reidLinden