В чем разница между DateTime.ToUniversalTime и TimeZoneInfo.ConvertTimeToUtc

StackOverflow https://stackoverflow.com/questions/1704780

  •  19-09-2019
  •  | 
  •  

Вопрос

Я только начинаю хорошенько задумываться о запуске веб-приложения, которое должно будет что-то делать для пользователей в начале их рабочего дня, скажем, в 6 утра.Тоже в конце своих дней.

Повсюду я читал о людях , которые много говорят просто для того , чтобы использовать .ToUniversalTime для сохранения времени в UTC, но когда я попробовал это (как я и подозревал), это не сработало, и это просто переместило время примерно на час (я нахожусь в Великобритании, поэтому я подумал, что это связано с некоторым смещением от GMT к UTC, хотя для меня это не имеет смысла, поскольку в данный момент режим экономии дневного света должен быть отключен).

У меня есть поле в базе данных, в котором хранится часовой пояс пользователей, и поэтому, когда я начал использовать ConvertTimeToUtc и fromUtc , оно начало делать то, что я ожидал от него.Хотя, опять же, я не уверен, должен ли я сам встроить какую-то логику для перехода на летнее время, или она должна сделать это за меня.

В основном мне интересно , о чем все говорили .В UniversalTime, поскольку это, похоже, действительно мне не помогло, и я не мог понять, как он вообще может знать, на сколько нужно откорректировать время, чтобы перевести его на UTC, тогда как второй способ имел смысл.

Может ли кто-нибудь объяснить, чем каждый из методов может быть полезен?

Это было полезно?

Решение

Если вы запустите код на компьютере в другом часовом поясе, будут ли ваши вычисления по-прежнему работать?Именно по этой причине люди хранят и обрабатывают все даты и времени как UTC - это устраняет любую двусмысленность.Вам не нужно было бы сохранять часовой пояс пользователя.Любой компьютер в любом месте может извлечь дату из базы данных и с легкостью преобразовать ее в местное время и обратно.

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

Другие советы

Там на самом деле является разница между этими двумя.

В .NET 3.5 и ниже, Datetime.ToUniversalTime реализуется как:

public DateTime ToUniversalTime() {
    return TimeZone.CurrentTimeZone.ToUniversalTime(this);
}

Потому что он использовал TimeZone класса, он страдал от тех же проблем, что и упомянутые в документы MSDN:

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

В .NET 4.0 и выше, Datetime.ToUniversalTime реализуется как:

public DateTime ToUniversalTime() { 
    return TimeZoneInfo.ConvertTimeToUtc(this, TimeZoneInfoOptions.NoThrowOnInvalidTime);
} 

Это устраняет проблему, связанную с отсутствием поддержки исторических правил корректировки, но из-за NoThrowOnInvalidTime Отметить, это не одно и то же как просто зовущий TimeZoneInfo.ConvertimeToUtc.

Метод, который он вызывает, является внутренний перегрузка ConvertTimeToUtc для этого требуется TimeZoneInfoOptions Отметить.В публичный версия метода использует TimeZoneInfoOptions.None, в то время как этот использует TimeZoneInfoOptions.NoThrowOnInvalidTime.

Разницу можно проиллюстрировать следующим образом.С часовым поясом, установленным на тихоокеанское время США:

DateTime dt = new DateTime(2015, 3, 8, 2, 0, 0, DateTimeKind.Local);
DateTime utc = dt.ToUniversalTime();
Console.WriteLine(utc); // "3/8/2015 10:00:00 AM"

Против:

DateTime dt = new DateTime(2015, 3, 8, 2, 0, 0, DateTimeKind.Local);
DateTime utc = TimeZoneInfo.ConvertTimeToUtc(dt);  // throws exception!
Console.WriteLine(utc);

Поскольку на эту дату в этом часовом поясе время переходит с 1:59:59 на 3:00:00, указание местного времени в 2:00:00 недопустимо.Правильное, что нужно сделать, это выдать исключение (как во втором случае).Однако, поскольку существующий контракт о DateTime.ToUniversalTime поскольку более ранние версии фреймворка не допускали этого, фреймворк выбирает возвращать значение вместо выбрасывания.

Выбранное значение вычисляется на основе использования стандартное время смещение, как если бы перехода в летнее время не произошло.

Редактировать:Я был неправ.Посмотрите на Мэтта Джонсона ответ для объяснения тонких различий между реализациями DateTime.ToUniversalTime и TimeZoneInfo.ConvertTimeToUtc.

Для всех остальных, у кого есть конкретный вопрос, сформулированный в названии: В чем разница между DateTime.ToUniversalTime и TimeZoneInfo.ConvertTimeToUtc?

Ответ таков: Здесь нет никакой разницы.

Использование JustDecompile для проверки реализации DateTime.ToUniversalTime в .NET 4.5 мы видим, что он использует TimeZoneInfo.ConvertTimeToUtc непосредственно:

    public DateTime ToUniversalTime()
    {
        return TimeZoneInfo.ConvertTimeToUtc(this, TimeZoneInfoOptions.NoThrowOnInvalidTime);
    }
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top