带有RTZ2时区的.Net Framework问题

我们似乎在.Net Framework 4.5中发现了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. 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 

任何想法如何解决这一问题?

这可能与KB3012229有关,后者已使用.NET 4.6修复。

如果安装了.NET 4.6,则不会抛出exception – 即使您的目标是.NET 4.0到4.5.2 – 因为它们都是就地升级。

如果您没有安装.NET 4.6,则exception在.NET 3.5 重现,或在.NET 4.0到.NET 4.5.2上重现。

你可以在这里做一些事情:

  • 选项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时区准确得多。 您可以在时区标签wiki中阅读更多内容。

试试这个:

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

您现在可以使用timeSpan创建UTC DateTime:

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