DateTime vs DateTimeOffset

В настоящее время у нас есть стандартный способ работы с .net DateTimes в часовом поясе: всякий раз, когда мы производим DateTime мы делаем это в UTC (например, используя DateTime.UtcNow), и всякий раз, когда мы показываем один, мы преобразуем обратно из UTC в локальное время пользователя.

это отлично работает, но я читал о DateTimeOffset и как он захватывает локальное и UTC время в самом объекте. Таким образом, вопрос в том, каковы были бы преимущества использования DateTimeOffset против того, что мы уже делать?

8 ответов


DateTimeOffset представление мгновенное время (также известный как времени). Под этим я подразумеваю момент времени, который универсален для всех (не считая високосных секунд, или релятивистские эффекты замедление времени). Другой способ представления мгновенного времени-с помощью DateTime здесь .Kind и DateTimeKind.Utc.

это отличается от календарного времени (также известный как гражданского времени), который является позицией в чьем-то календаре, и есть много разных календарей по всему миру. Мы называем эти календари часовых поясов. Календарное время представлено DateTime здесь .Kind и DateTimeKind.Unspecified или DateTimeKind.Local. И .Local имеет смысл только в сценариях, где у вас есть подразумеваемое понимание того, где расположен компьютер, который использует результат. (Например, рабочая станция пользователя)

так почему же DateTimeOffset вместо UTC DateTime? все дело в перспективе. давайте проведем аналогию-притворимся фотографами.

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

человек, стоящий на фотографии, увидит угол, под которым появилась ваша камера. Если кто-то фотографировал, то под разными углами. Это Offset часть DateTimeOffset представляет.

поэтому, если вы помечаете свою камеру "Восточное время", иногда вы указываете от -5, а иногда вы указываете от -4. Есть камеры по всему миру, все помечены разными вещами, и все направлены в то же мгновение временная шкала под разными углами. Некоторые из них находятся рядом (или поверх) друг друга, поэтому просто знать смещение недостаточно, чтобы определить, с каким часовым поясом связано время.

а как насчет UTC? Ну, это единственная камера, которая гарантированно имеет твердую руку. Он на треноге, прочно закреплен в земле. Она никуда не денется. Мы называем его угол зрения нулем. сдвиг.

Instantaneous Time vs Calendar Time Visualization

Итак, что говорит нам эта аналогия? Он дает некоторые интуитивные рекомендации.

  • если вы представляете время относительно некоторого места в частности, представить его в календарное время с DateTime. Просто убедитесь, что вы никогда не путаете один календарь с другим. Unspecified должно быть ваше предположение. Local полезно только из DateTime.Now. Например, я могу получить DateTime.Now и сохранить его в базе данных - но когда я получаю его, я должен предположить, что это Unspecified. Я не могу полагаться на то, что мой местный календарь-это тот же календарь, из которого он был первоначально взят.

  • если вы всегда должны быть уверены в моменте, убедитесь, что вы представляете мгновенное время. Использовать DateTimeOffset для его применения или использования UTC DateTime по Конвенции.

  • Если вам нужно отслеживать момент мгновенного времени, но вы также Хотите знать, " какое время пользователь думал это было в их местном календаре?- ...тогда ты! .. --39-->должны использовать DateTimeOffset. Это очень важно для систем хронометража, например - как для технических, так и для юридических вопросов.

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

    следует также отметить, что Нода Времени имеет представление под названием ZonedDateTime для этого, в то время как библиотека базовых классов .Net не имеет ничего подобного. Вам нужно будет сохранить оба DateTimeOffset и TimeZoneInfo.Id значение.

  • иногда вы захотите представить календарное время, которое является локальным для "того, кто смотрит на него". Например, при определении что?!-Сегодня -39--> средства. Сегодня ВСЕГДА полночь до полуночи, но они представляют собой почти бесконечное количество перекрывающихся диапазонов на мгновенной временной шкале. (На практике у нас есть конечное количество часовых поясов, но вы можете выразить смещения вплоть до галочки) поэтому в этих ситуациях убедитесь, что вы понимаете, как ограничить "кто спрашивает?"вопрос вниз в один часовой пояс, или иметь дело с переводом их обратно в мгновенное время, как соответствующий.

вот еще несколько маленьких кусочков о DateTimeOffset это подкрепляет эту аналогию и некоторые советы для поддержания ее прямо:

  • если вы сравните два DateTimeOffset значения, они сначала нормализуются до нулевого смещения перед сравнением. Другими словами,2012-01-01T00:00:00+00:00 и 2012-01-01T02:00:00+02:00 относятся к одному и тому же мгновенному моменту и, следовательно, эквивалентны.

  • если вы делаете любое модульное тестирование и должны быть некоторые из смещения, test и на DateTimeOffset значение, а .Offset собственность отдельно.

  • существует одностороннее неявное преобразование, встроенное в .Net framework, которое позволяет передавать DateTime в любом DateTimeOffset параметр или переменная. При этом the .Kind вопросы. Если вы передадите вид UTC, он будет нести с нулевым смещением, но если вы передадите либо .Local или .Unspecified, он будет считать местные. Структура в основном говорит: "Ну, вы попросили меня преобразовать календарное время в мгновенное время, но я понятия не имею, откуда это взялось, поэтому я просто собираюсь использовать местный календарь."Это огромная gotcha, если вы загружаете неопределенный DateTime на компьютере с другим часовым поясом. (ИМХО - это должно вызвать исключение - но это не так.)

Промоушен:

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


От Microsoft:

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

источник: "выбор между DateTime, DateTimeOffset, TimeSpan и TimeZoneInfo", MSDN

мы используем:DateTimeOffset почти все наши приложение имеет дело с конкретными моментами времени (например, когда запись была создана/обновлена). В качестве примечания мы используем DATETIMEOFFSET в SQL Server 2008, а также.

я вижу DateTime как полезно, когда вы хотите иметь дело только с датами, только раз или иметь дело с любым в общем смысле. Например, если у вас есть будильник, который вы хотите выключать каждый день в 7 утра, вы можете сохранить это в DateTime используя DateTimeKind of Unspecified потому что вы хотите, чтобы он взорвался в 7 утра независимо от DST. Но если вы хотите представить историю возникновения тревоги, вы должны использовать DateTimeOffset.

будьте осторожны при использовании смеси DateTimeOffset и DateTime особенно при назначении и сравнении между типами. Кроме того, только сравнить DateTime экземпляры, которые одинаковы DateTimeKind, потому что DateTime игнорирует смещение часового пояса при сравнении.


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

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


есть несколько мест, где DateTimeOffset имеет смысл. Когда вы имеете дело с повторяющимися событиями и летнее время. Допустим, я хочу установить будильник на 9 утра каждый день. Если я использую правило "store as UTC, display as local time", то сигнал тревоги будет отключен в разные время, когда летнее время в силе.

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


самое важное различие заключается в том, что DateTime не хранит информацию о часовом поясе, а DateTimeOffset.

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

например, если сериализовать значение DateTime с помощью Kind=Local Json.Net и формат даты ISO, вы получите строку, как 2015-08-05T07:00:00-04. Обратите внимание, что последняя часть (-04) не имеет никакого отношения к вашему DateTime или любому смещению, которое вы использовали для его вычисления... это просто смещение часового пояса сервера.

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


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


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

это полезно для серверного приложения (например ASP.NET) который доступен пользователям в разных часовых поясах.


единственная отрицательная сторона DateTimeOffset я вижу, что Microsoft "забыл" (по дизайну), чтобы поддержать его в своем классе XmlSerializer. Но с тех пор он был добавлен в служебный класс XmlConvert.

XmlConvert.ToDateTimeOffset

XmlConvert.Метод toString

Я говорю идти вперед и использовать DateTimeOffset и TimeZoneInfo из-за всех преимуществ, просто будьте осторожны при создании объектов, которые будут или могут быть сериализованы В или из XML (тогда все бизнес-объекты).