.Net Framework 问题与 RTZ2 时区
.Net Framework issue with RTZ2 time zone
我们似乎发现了 .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.
示例 (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
有什么解决办法吗?
试试这个:
var rtz2 = TimeZoneInfo.FindSystemTimeZoneById("Russian Standard Time");
var offset = new DateTimeOffset(new DateTime(2014, 1, 1));
var timeSpan = rtz2.GetUtcOffset(offset);
您现在可以使用 timeSpan 创建 UTC 日期时间:
var utc = offset.Add(timeSpan);
// 1/1/2014 4:00:00 AM -06:00
这可能与 KB3012229 有关,后者已在 .NET 4.6 中修复。
如果您安装了 .NET 4.6,则不会抛出异常 - 即使您的目标是 .NET 4.0 到 4.5.2 - 因为它们都是就地升级。
如果您没有安装 .NET 4.6,异常 会 在 .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 and 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.
中阅读更多内容
我们似乎发现了 .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.
示例 (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
有什么解决办法吗?
试试这个:
var rtz2 = TimeZoneInfo.FindSystemTimeZoneById("Russian Standard Time");
var offset = new DateTimeOffset(new DateTime(2014, 1, 1));
var timeSpan = rtz2.GetUtcOffset(offset);
您现在可以使用 timeSpan 创建 UTC 日期时间:
var utc = offset.Add(timeSpan);
// 1/1/2014 4:00:00 AM -06:00
这可能与 KB3012229 有关,后者已在 .NET 4.6 中修复。
如果您安装了 .NET 4.6,则不会抛出异常 - 即使您的目标是 .NET 4.0 到 4.5.2 - 因为它们都是就地升级。
如果您没有安装 .NET 4.6,异常 会 在 .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 and 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.
中阅读更多内容