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
для принудительного применения или используйте UTC DateTime
по соглашению.
Если вам нужно отследить мгновенное время, но вы также хотите знать, «во сколько время пользователь думал, что это было в его локальном календаре?» - тогда вы должны использовать DateTimeOffset
. Это очень важно, например, для систем хронометража - как для технических, так и для юридических вопросов.
Если вам когда-либо понадобится изменить ранее записанный файл DateTimeOffset
- у вас недостаточно информации только для одного смещения, чтобы гарантировать, что новое смещение по-прежнему актуально для пользователя. Вы также должны сохранить идентификатор часового пояса (подумайте - мне нужно имя этой камеры, чтобы я мог сделать новый снимок, даже если положение изменилось).
Следует также отметить, что для этого у Noda Time есть представление ZonedDateTime
, в то время как библиотека базовых классов .Net не имеет ничего подобного. Вам нужно будет хранить как a, так DateTimeOffset
и TimeZoneInfo.Id
значение.
Иногда вам может потребоваться указать календарное время, которое является локальным для «того, кто смотрит на него». Например, при определении того, что сегодня означает. Сегодня всегда полночь - полночь, но они представляют собой почти бесконечное количество перекрывающихся диапазонов на мгновенной временной шкале. (На практике у нас есть ограниченное количество часовых поясов, но вы можете выразить смещения вплоть до отметки). Поэтому в этих ситуациях убедитесь, что вы понимаете, как ограничить «кто спрашивает?» вопрос до одного часового пояса, или сделайте перевод их обратно в мгновенное время по мере необходимости.
Вот еще несколько маленьких подробностей об DateTimeOffset
этой аналогии, а также несколько советов, как сохранить ее прямо:
Если вы сравниваете два DateTimeOffset
значения, они сначала нормализуются к нулевому смещению перед сравнением. Другими словами, 2012-01-01T00:00:00+00:00
и 2012-01-01T02:00:00+02:00
относятся к одному и тому же мгновенному моменту и, следовательно, эквивалентны.
Если вы делаете какие - либо модульного тестирования и должны быть уверены в офсетной, испытания как в DateTimeOffset
стоимости, и .Offset
собственности отдельно.
В платформу .Net встроено одностороннее неявное преобразование, которое позволяет передавать a DateTime
в любой DateTimeOffset
параметр или переменную. При этом, вопросы . Если вы передаете тип UTC, он будет иметь нулевое смещение, но если вы передадите либо, либо , он будет локальным . Фреймворк в основном говорит: «Ну, вы попросили меня перевести календарное время в мгновенное, но я понятия не имею, откуда это пришло, поэтому я просто собираюсь использовать местный календарь». Это огромная ошибка, если вы загружаете неопределенное на компьютер с другим часовым поясом. (ИМХО - это должно вызвать исключение - но это не так.).Kind
.Local
.Unspecified
DateTime
Бесстыдная вилка:
Многие люди поделились со мной, что они находят эту аналогию чрезвычайно полезной, поэтому я включил ее в свой курс по Pluralsight, «Основы даты и времени» . Вы найдете пошаговое руководство по аналогии с камерой во втором модуле «Вопросы контекста» в клипе под названием «Время календаря и мгновенное время».