Как работает DateTime.ToUniversalTime ()? - PullRequest
60 голосов
/ 29 июля 2009

Как работает преобразование в UTC из стандартного формата DateTime?

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

Ответы [ 4 ]

71 голосов
/ 29 июля 2009

Не существует неявного часового пояса, прикрепленного к объекту DateTime. Если вы запускаете ToUniversalTime() на нем, он использует часовой пояс контекста, в котором выполняется код.

Например, если я создаю DateTime из эпохи 01.01.1970, это дает мне один и тот же DateTime объект, независимо от того, где я нахожусь.

Если я запускаю ToUniversalTime() на нем, когда я запускаю код в Гринвиче, то я получаю то же самое время. Если я сделаю это, пока живу в Ванкувере, то получу смещение DateTime объекта -8 часов.

Вот почему важно хранить информацию о времени в вашей базе данных как время UTC, когда вам необходимо выполнить преобразование или локализацию любого вида. Подумайте, не переместилась ли ваша кодовая база на сервер в другом часовом поясе;)

Редактировать: заметка из ответа Джоэла - DateTime объекты по умолчанию набираются как DateTimeKind.Local. Если вы анализируете дату и устанавливаете ее как DateTimeKind.Utc, ToUniversalTime() не выполняет преобразование.

А вот статья о «Наилучшие методы кодирования с датой и временем» и статья о Преобразовании дат времени с.

33 голосов
/ 29 июля 2009

Во-первых, он проверяет, известно ли, что Kind из DateTime является UTC. Если это так, он возвращает то же значение.

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

Часовой пояс содержит достаточно информации, чтобы преобразовать местное время в UTC или наоборот, хотя бывают случаи, когда это неоднозначно или недопустимо. (Существуют локальные времена, которые происходят дважды, и локальные времена, которые никогда не происходят из-за перехода на летнее время.) Правила обработки этих случаев указаны в документации :

Если значение экземпляра даты и времени равно неоднозначное время, этот метод предполагает что это стандартное время. (An неоднозначное время - это то, что может отображать или к стандартному времени или к летнее время по местному времени зона) Если дата и время экземпляра значение является неверным временем, этот метод просто вычитает местное время из смещение UTC местного часового пояса к возврат UTC. (Недопустимое время что не существует из-за применение летнего времени Правила корректировки.)

Возвращаемое значение будет иметь Kind из DateTimeKind.Utc, поэтому, если вы вызовете ToUniveralTime, оно не будет применять смещение снова. (Это значительное улучшение по сравнению с .NET 1.1!)

Если вы хотите использовать нелокальный часовой пояс, вы должны использовать TimeZoneInfo, который был представлен в .NET 3.5 (есть хакерские решения для более ранних версий, но они не очень хороши). Чтобы представить момент времени, вы должны рассмотреть возможность использования DateTimeOffset, который был представлен в .NET 2.0SP1, .NET3.0SP1 и .NET 3.5. Однако, это все еще не имеет фактического часового пояса, связанного с ним - только смещение от UTC. Это означает, что вы не знаете, какое местное время будет, например, через час - правила перехода на летнее время могут различаться в зависимости от часовых поясов, в которых в тот или иной момент использовалось одно и то же смещение. TimeZoneInfo предназначен для учета исторических и будущих правил, в отличие от TimeZone, что несколько упрощенно.

По сути, поддержка в .NET 3.5 намного лучше, чем была, но все же оставляет желать лучшего для правильной календарной арифметики. Кто-нибудь хочет перенести Joda Time на .NET? ;)

7 голосов
/ 29 июля 2009

Что @ womp сказал , кроме того, что он проверяет свойство Kind DateTime, чтобы узнать, может ли уже быть датой UTC.

3 голосов
/ 29 июля 2009

DateTime.ToUniversalTime удаляет смещение часового пояса местного часового пояса, чтобы нормализовать DateTime к UTC. Если затем вы используете DateTime.ToLocalTime для нормализованного значения в другом часовом поясе, смещение часового пояса этого часового пояса будет добавлено к нормализованному значению для правильного представления в этом часовом поясе.

...