Получить DateTimeOffset из DateTime (utc) и TimeZoneInfo
Мне нужно преобразовать DateTime + TimeZoneInfo в DateTimeOffset.
Как мне это сделать? Я предполагаю, что должен пройти TimeSpan, но тогда я не уверен, будет ли обработать летнее время.
Спасибо!
UPDATE
TimeZoneInfo timeZone = TimeZoneInfo.FindSystemTimeZoneById("Mountain Standard Time");
return new DateTimeOffset(DateTime.UtcNow, timeZone.BaseUtcOffset);
Этот код генерирует исключение.
Смещение UTC для Utc DateTime экземпляры должны быть равны 0.\r\nПараметр name: offset
ОБНОВЛЕНИЕ 2
Извините, я не понимал, что DateTimeOffset содержит только смещение, оно не содержит актуальной информации о зоне - поэтому я принимаю ответ от @Dave, поскольку это то, что я буду использовать.
Ответы
Ответ 1
Вы должны получить разницу между DateTime.UtcNow и DateTime.Now
var now = DateTime.Now;
var utcNow = now.ToUniversalTime();
var ts = utcNow - now;
Если вы сохраняете смещение, обычно полезно сохранять все даты в формате UTC (особенно в db), поэтому вам не придется иметь дело с смещениями. Вы просто конвертируете их перед отображением, но выполняете все вычисления в формате UTC.
Изменить: если у вас есть объект TimeZone, вы можете преобразовать дату UTC в локальное время для этого часового пояса.
TimeZone.CurrentTimeZone.ToLocalTime()
ИЛИ
DateTime dt = TimeZoneInfo.ConvertTimeFromUtc()
Вот пример кода, который будет отображать дату во всех часовых поясах.
var dt = new DateTime(2011, 5, 21, 11, 0, 0);
foreach (var tzi in TimeZoneInfo.GetSystemTimeZones())
{
Console.WriteLine(string.Format("Time in {0} is {1}", tzi.DisplayName, TimeZoneInfo.ConvertTimeFromUtc(dt, tzi)));
}
Ответ 2
TimeZoneInfo
имеет свойство BaseUtcOffset
, которое является TimeSpan
, представляющим смещение.
Это смещение, которое конструкторы DateTimeOffset
ожидают:
var myDTOffset = new DateTimeOffset(myDatetime, mytzInfo.BaseUtcOffset);
Ответ 3
Я думаю, что может быть проще устранить ошибку. Вы пробовали:
TimeZoneInfo timeZone = TimeZoneInfo.FindSystemTimeZoneById("Mountain Standard Time");
return new DateTimeOffset(DateTime.UtcNow, timeZone.BaseUtcOffset);
DateTimeOffset выдает исключение. Что вы хотели, так это:
TimeZoneInfo timeZone = TimeZoneInfo.FindSystemTimeZoneById("Mountain Standard Time");
return new DateTimeOffset(DateTime.UtcNow).ToOffset(timeZone.BaseUtcOffset);
Это не вызовет исключения. Я не уверен, почему конструктор, который принимает TimeSpan, даже существует, поскольку он работает только в том случае, если он соответствует локальному или utc-смещению, указанному в объекте DateTime. Но это все еще возможно при меньшей головной боли.
Ответ 4
Для тех из нас, кто работает с устаревшими системами, не всегда возможно изменить способ хранения данных. Если вас интересует только конкретный часовой пояс на компьютере, с которого работает ваш код, вы можете использовать следующий метод расширения. Существует неявное преобразование между DateTime и DateTimeOffset, которое учитывает свойство DateTime.Kind.
public static DateTimeOffset ToDateTimeOffset(this DateTime dt)
{
return DateTime.SpecifyKind(dt, DateTimeKind.Local);
}