DateTime vs DateTimeOffset
В настоящее время у нас есть стандартный способ иметь дело с .net DateTimes в методе TimeZone: всякий раз, когда мы создаем DateTime
мы делаем это в UTC (например, используя DateTime.UtcNow
), и всякий раз, когда мы показываем его, мы конвертируем обратно с UTC на местное время пользователя.
Это работает отлично, но я читал о DateTimeOffset
и о том, как он фиксирует время локального и UTC в самом объекте. Итак, вопрос в том, каковы были бы преимущества использования DateTimeOffset
сравнении с тем, что мы уже делали?
- Каков часовой пояс по умолчанию в java.util.Date
- Лучшее время для летнего времени и часовых поясов
- JSF convertDateTime с часовым поясом в datatable
- Как бороться с проблемой часового пояса при хранении дат в utc с использованием mongod?
- В каком часовом поясе отображается Date.toString ()?
- Любая разница между java.time.Clock.systemDefaultZone (). GetZone () vs java.util.TimeZone.getDefault (). ToZoneId ()?
- Получить время определенного часового пояса
- Как анализировать дату с GMT TimeZone на IST TimeZone и наоборот в android
- Как установить часовой пояс java.util.Date?
- Поиск временной зоны по широте долготы
- Как получить текущую дату и время в UTC или GMT на Java?
- Является ли java.util.Date использованием TimeZone?
- Преобразование даты времени из часового пояса в часовой пояс в sql-сервере
DateTimeOffset
представляет собой представление мгновенного времени (также известного как абсолютное время ). Таким образом, я имею в виду момент времени, который является универсальным для всех (не считая скачкообразных секунд или релятивистских эффектов замедления времени ). Другим способом представления мгновенного времени является DateTime
где .Kind
– DateTimeKind.Utc
.
Это отличается от календарного времени (также известного как гражданское время ), что является позицией в чьем-то календаре, и существует множество разных календарей по всему миру. Мы называем эти временные зоны календарей. Время календаря представлено DateTime
где .Kind
– DateTimeKind.Unspecified
или DateTimeKind.Local
. И .Local
имеет смысл только в сценариях, где у вас подразумевается понимание того, где находится компьютер, который использует результат. (Например, рабочая станция пользователя)
Итак, почему DateTimeOffset
вместо UTC DateTime
? Это все о перспективах. Давайте используем аналогию – мы будем притворяться фотографами.
Представьте, что вы стоите на календарной шкале времени, указывая на камеру у человека на мгновенной временной шкале, изложенной перед вами. Вы выстраиваете свою камеру в соответствии с правилами вашего часового пояса, которые периодически меняются из-за летнего времени или из-за других изменений в юридическом определении вашего часового пояса. (У вас нет устойчивой руки, поэтому ваша камера шаткая.)
Человек, стоящий на фотографии, увидит угол, из которого появилась ваша камера. Если другие фотографируют, они могут быть под разными углами. Это то, что представляет собой Offset
часть DateTimeOffset
.
Поэтому, если вы помечаете свою камеру «Восточное время», иногда вы указываете от -5, а иногда вы указываете от -4. Есть камеры по всему миру, все обозначенные разными вещами, и все они указывают на одну и ту же мгновенную временную шкалу под разными углами. Некоторые из них находятся рядом с (или сверху) друг с другом, поэтому просто знать, что смещение недостаточно для определения того, к какому временному времени относится время.
А как насчет UTC? Ну, это единственная камера, которая гарантирована устойчивой рукой. Он на штативе, крепко привязан к земле. Это никуда не денется. Мы называем его угол зрения нулевым смещением.
Итак, что говорит эта аналогия? Он содержит некоторые интуитивные рекомендации.
-
Если вы представляете время относительно некоторого места в частности, представляйте его в календарном времени с помощью
DateTime
. Просто убедитесь, что вы никогда не путаете один календарь с другим.Unspecified
должно быть вашим предположением.Local
полезен только сDateTime.Now
. Например, я могу получитьDateTime.Now
и сохранить его в базе данных, но когда я его извлечу, я должен предположить, что он неUnspecified
. Я не могу полагаться на то, что мой местный календарь – это тот же календарь, из которого он был первоначально взят. -
Если вы всегда должны быть уверены в этом, убедитесь, что вы представляете мгновенное время. Используйте
DateTimeOffset
для принудительного использования или используйте UTCDateTime
по соглашению. -
Если вам нужно отслеживать мгновение мгновенного времени, но вы также хотите знать: «В какое время пользователь подумал, что это был в их местном календаре?» – тогда вы должны использовать
DateTimeOffset
. Это очень важно для систем учета времени, например, как для технических, так и юридических проблем. -
Если вам когда-либо понадобится изменить ранее записанный
DateTimeOffset
– у вас недостаточно информации только в смещении, чтобы убедиться, что новое смещение все еще актуально для пользователя. Вы также должны сохранить идентификатор часового пояса (подумайте – мне нужно имя этой камеры, чтобы я мог снимать новое изображение, даже если позиция изменилась).Следует также отметить, что Noda Time имеет для этого представление
ZonedDateTime
, в то время как библиотека базового classа .Net не имеет ничего подобного. Вам нужно будет сохранить значениеDateTimeOffset
и значениеTimeZoneInfo.Id
. -
Иногда вы хотите представить время календаря, которое является локальным, «кто его смотрит». Например, при определении того, что сегодня означает. Сегодня всегда полночь до полуночи, но они представляют собой почти бесконечное количество перекрывающихся диапазонов на мгновенной временной шкале. (На практике у нас есть конечное количество часовых поясов, но вы можете выразить смещения до отметки). Поэтому в этих ситуациях убедитесь, что вы понимаете, как ограничить «кто спрашивает?». задайте вопрос до одного часового пояса или займитесь переводом их обратно в мгновенное время по мере необходимости.
Вот несколько других небольших бит о DateTimeOffset
которые поддерживают эту аналогию, и некоторые советы по ее сохранению:
-
Если вы сравниваете два значения
DateTimeOffset
, они сначала нормализуются до нулевого смещения перед сравнением. Другими словами,2012-01-01T00:00:00+00:00
и2012-01-01T02:00:00+02:00
относятся к одному и тому же мгновенному моменту и поэтому эквивалентны. -
Если вы выполняете какое-либо модульное тестирование и должны быть уверены в смещении, проверьте как значение
DateTimeOffset
, так и свойство.Offset
отдельно. -
Существует одностороннее неявное преобразование, встроенное в .Net-структуру, которая позволяет передавать
DateTime
в любой параметр или переменнуюDateTimeOffset
. При этом.Kind
значение.Kind
. Если вы передадите тип UTC, он будет переноситься с нулевым смещением, но если вы пройдете либо.Unspecified
или.Unspecified
, он будет считаться локальным . Рамки в основном говорят: «Ну, вы попросили меня преобразовать время календаря в мгновенное время, но я понятия не имею, откуда это взялось, поэтому я просто собираюсь использовать местный календарь». Это огромная ошибка, если вы загружаете неопределенныйDateTime
на компьютер с другим часовым поясом. (ИМХО – это должно выставить исключение – но это не так.)
Бесстыдный штекер:
Многие люди поделились со мной тем, что они считают эту аналогию чрезвычайно ценной, поэтому я включил ее в мой курс Pluralsight, Date and Time Fundamentals . Вы найдете пошаговое руководство по аналогии с камерой во втором модуле «Контекстные вопросы» в клипе под названием «Время календаря против мгновенного времени».
От Microsoft:
Эти значения для значений DateTimeOffset гораздо более распространены, чем значения для значений DateTime. В результате DateTimeOffset следует рассматривать как тип даты и времени по умолчанию для разработки приложений.
источник: «Выбор между DateTime, DateTimeOffset, TimeSpan и TimeZoneInfo» , MSDN
Мы используем DateTimeOffset
почти для всех, так как наше приложение имеет дело с определенными моментами времени (например, когда запись была создана / обновлена). В качестве дополнительной заметки мы также используем DATETIMEOFFSET
в SQL Server 2008.
Я вижу, что DateTime
полезен, когда вы хотите иметь дело только с датами, только временами, или иметь дело либо в общем смысле. Например, если у вас есть будильник, который вы хотите отключать каждый день в 7 утра, вы можете сохранить это в DateTime
используя DateTimeKind
Unspecified
потому что вы хотите, чтобы он ушел в 7 утра, независимо от DST. Но если вы хотите представить историю возникновения тревоги, вы должны использовать DateTimeOffset
.
Соблюдайте осторожность при использовании комбинации DateTimeOffset
и DateTime
особенно при назначении и сравнении типов. Кроме того, сравнивайте только экземпляры DateTime
которые являются тем же самым DateTimeKind
потому что DateTime
игнорирует смещение часового пояса при сравнении.
DateTime может хранить только два отдельных раза, местное время и UTC. Свойство Kind указывает, какой.
DateTimeOffset расширяет это, сохраняя локальные времена из любой точки мира. Он также сохраняет смещение между этим местным временем и UTC. Обратите внимание, что DateTime не может это сделать, если вы не добавите дополнительный член в свой class, чтобы сохранить это смещение UTC. Или только работайте с UTC. Что само по себе является прекрасной идеей кстати.
Есть несколько мест, где DateTimeOffset
имеет смысл. Первый – когда вы имеете дело с повторяющимися событиями и летним временем. Предположим, я хочу настроить будильник, чтобы выходить в 9 утра каждый день. Если я использую правило «магазин как UTC, отображаемое как локальное время», тогда будильник будет уходить в другое время, когда действует летнее время.
Возможно, есть и другие, но приведенный выше пример – это тот, который я использовал в прошлом (это было до добавления 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 для получения дополнительной информации.
- Краткая история DateTime – Энтони Мур из команды BCL
- Выбор между Datetime и DateTime Offset – с помощью MSDN
- Не забывайте, что SQL Server 2008 имеет новый тип данных как DateTimeOffset
- .NET Framework включает типы DateTime , DateTimeOffset и TimeZoneInfo , все из которых могут быть использованы для создания приложений, работающих с датами и временем.
- Выполнение арифметических операций с датами и временем-MSDN
Основное отличие заключается в том, что DateTimeOffset
может использоваться совместно с TimeZoneInfo
для преобразования в локальные времена в часовых поясах, отличных от текущего.
Это полезно для серверного приложения (например, ASP.NET), доступ к которому осуществляется пользователями в разных часовых поясах.
Единственная отрицательная сторона DateTimeOffset, которую я вижу, – это то, что Microsoft «забыла» (по дизайну), чтобы поддерживать ее в своем classе XmlSerializer. Но с тех пор он добавлен в class утилиты XmlConvert.
XmlConvert.ToDateTimeOffset
XmlConvert.ToString
Я говорю, продолжайте использовать DateTimeOffset и TimeZoneInfo из-за всех преимуществ, просто будьте осторожны при создании объектов, которые будут или могут быть сериализованы в XML или из него (все бизнес-объекты затем).