В чем разница между DateTime.ToUniversalTime и TimeZoneInfo.ConvertTimeToUtc
Вопрос
Я только начинаю хорошенько задумываться о запуске веб-приложения, которое должно будет что-то делать для пользователей в начале их рабочего дня, скажем, в 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);
}