Подтвердить что ты не робот

Получить 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, поскольку это то, что я буду использовать.

4b9b3361

Ответ 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);
}