Ответ 1
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
для этого, в то время как библиотека базового класса .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
имеет значение. Если вы передадите тип UTC, он будет переноситься с нулевым смещением, но если вы пройдете либо.Local
, либо.Unspecified
, он будет считаться локальным. Рамки в основном говорят: "Ну, вы попросили меня преобразовать время календаря в мгновенное время, но я понятия не имею, откуда это взялось, поэтому я просто собираюсь использовать локальный календарь". Это огромная проблема, если вы загружаете неуказанныйDateTime
на компьютер с другим часовым поясом. (IMHO - это должно вызывать исключение - но это не так.)
Бесстыдный плагин:
Многие люди поделились со мной тем, что они считают эту аналогию чрезвычайно ценной, поэтому я включил ее в курс Pluralsight, Основы даты и времени. Вы найдете пошаговое руководство по аналогии с камерой во втором модуле "Контекстные вопросы" в клипе "Время календаря против мгновенного времени".