2015-08-28 3 views
3

Похоже, что мы обнаружили проблему с часовым поясом RTZ2 (Русский Стандартное время) в .Net Framework 4.5..Net Framework с часовым поясом RTZ2

Если вы пытаетесь преобразовать время между 2014-01-01 00:00:00 и 2014-01-01 00:59:59 (в RTZ2 часовой пояс) в UTC, вы получите сообщение об ошибке: The supplied DateTime represents an invalid time. For example, when the clock is adjusted forward, any time in the period that is skipped is invalid.

Пример (https://dotnetfiddle.net/rNbp8F):

var rtz2 = TimeZoneInfo.FindSystemTimeZoneById("Russian Standard Time"); 
var moment = new DateTime(2014, 1, 1); 
var utc = TimeZoneInfo.ConvertTimeToUtc(moment, rtz2); // throws an exception 

Любые идеи, как это исправить?

+0

Хорошо работает, вы должны документировать свой часовой пояс. Также маловероятно, что у вас есть 4.5 –

+0

@HansPassant - местный часовой пояс не входит в игру с предоставленным кодом. –

ответ

2

Это, вероятно, связано с KB3012229, которая была установлена ​​с .NET 4.6.

Если у вас установлен .NET 4.6, исключение не будет выбрано - даже если вы настроили таргетинг на .NET 4.0 - 4.5.2 - потому что все они обновлены на месте.

Исключение делает воспроизводит на .NET 3.5 или на .NET 4.0 до .NET 4.5.2, если у вас нет установленной версии .NET 4.6.

Есть несколько вещей, которые вы можете сделать здесь:

  • Вариант 1: Оставьте свой код, как есть, и обновление до последней .NET 4.6 (или установить один из исправлений теперь доступны в статье KB)

  • Вариант 2: Изменить код, чтобы использовать функцию, например, следующим образом:

    private DateTime Rtz2ToUtc(DateTime dt) 
    { 
        if (dt.Kind == DateTimeKind.Utc) 
         return dt; 
    
        if (dt.Year < 2011) 
        { 
         var tz = TimeZoneInfo.FindSystemTimeZoneById("Russian Standard Time"); 
         return TimeZoneInfo.ConvertTimeToUtc(dt, tz); 
        } 
    
        var transition = new DateTime(2014, 10, 26, 2, 0, 0); 
        var offset = TimeSpan.FromHours(dt < transition ? 4 : 3); 
        return new DateTimeOffset(dt, offset).UtcDateTime; 
    } 
    
  • Вариант 3: Изменить код, чтобы использовать Noda Time и TZDB часовых пояса:

    private DateTime Rtz2ToUtc(DateTime dt) 
    { 
        if (dt.Kind == DateTimeKind.Utc) 
         return dt; 
    
        DateTimeZone tz = DateTimeZoneProviders.Tzdb["Europe/Moscow"]; 
        LocalDateTime ldt = LocalDateTime.FromDateTime(dt); 
        return ldt.InZoneLeniently(tz).ToDateTimeUtc(); 
    } 
    

Лично я предпочитаю вариант 3, поскольку TZDB часовых пояса намного более точны, чем часовые пояса Windows. Вы можете прочитать больше в the timezone tag wiki.

-1

Попробуйте это:

var rtz2 = TimeZoneInfo.FindSystemTimeZoneById("Russian Standard Time"); 
var offset = new DateTimeOffset(new DateTime(2014, 1, 1)); 
var timeSpan = rtz2.GetUtcOffset(offset); 

Теперь вы можете создать UTC DateTime с помощью TimeSpan:

var utc = offset.Add(timeSpan); 
// 1/1/2014 4:00:00 AM -06:00 
+0

Построение 'DateTimeOffset' из' DateTime' с 'DateTimeKind.Unspecified' предполагает локальный часовой пояс компьютера *. –

Смежные вопросы