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за умовами.
Якщо вам потрібно відстежити момент миттєвого часу, але ви хочете також знати "Який час користувач думав, що це в їхньому місцевому календарі?" - тоді ви повинні використовувати a 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параметра або змінної. При цьому, питання . Якщо ви передаєте тип UTC, він здійснюватиметься з нульовим зміщенням, але якщо ви передасте або, або він вважатиметься локальним . В основному рамки говорять: "Ну, ви попросили мене перетворити календарний час на миттєвий час, але я не маю уявлення, звідки це взялося, тому я просто збираюся використовувати місцевий календар". Це величезна проблема, якщо ви завантажуєте не визначене на комп'ютер з іншим часовим поясом. (IMHO - це повинно кинути виняток, але це не так.).Kind.Local.UnspecifiedDateTime
Безсоромний штекер:
Багато людей поділилися зі мною, що вважають цю аналогію надзвичайно цінною, тому я включив її у свій курс з питань плюралізму, Основи дати та часу . Покрокове ознайомлення з аналогією камери ви знайдете у другому модулі "Контекстні питання" у кліпі під назвою "Час календаря проти миттєвого часу".