.NET跟踪一些的历史,但它并不总是准确的。你偶然发现了一个不准确的地方。
.NET通过注册表从Windows导入其所有的时区信息,如here和here所述。如果您在注册表HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Time Zones\Russian Standard Time\Dynamic DST
处查看,您会发现它仅跟踪2010年前往该时区的信息。 2000年的测试日期不会很好,因为它会回落到最早的规则(2010年)。
基地UTC偏移信息是在注册表中的跟踪,但不在是.NET进口入AdjustmentRule
类。如果检查调整规则的时区,你会发现,2012年和2013没有在全部进口:
var tz = TimeZoneInfo.FindSystemTimeZoneById("Russian Standard Time");
foreach (var rule in tz.GetAdjustmentRules())
{
Console.WriteLine("{0:d} - {1:d}", rule.DateStart, rule.DateEnd);
}
OUTPUT:
1/1/0001 - 12/31/2010
1/1/2011 - 12/31/2011
1/1/2014 - 12/31/2014
即使他们在Windows注册表中存在,由于没有夏令时调整,因此2012年和2013年不会导入。
这会在基准偏移量发生变化时产生问题 - 就像它在此时区一样。由于它目前为+3,并且两年内没有导入+4,所以对于那些错过的年份它看起来就是+3。
使用TimeZoneInfo
没有好的解决方案。即使您尝试创建自己的自定义时区,在将这种更改适用于可用的数据结构时也会遇到问题。
幸运的是,还有另一种选择。您可以使用标准IANA time zones,通过Noda Time库。
下面的代码使用野田的时间来匹配你在你原来的代码中写道:
DateTimeZone tz = DateTimeZoneProviders.Tzdb.GetSystemDefault();
Console.WriteLine(Instant.FromUtc(2012, 1, 1, 0, 0).InZone(tz).LocalDateTime);
Console.WriteLine(Instant.FromUtc(2012, 6, 1, 0, 0).InZone(tz).LocalDateTime);
Console.WriteLine(Instant.FromUtc(2000, 1, 1, 0, 0).InZone(tz).LocalDateTime);
Console.WriteLine(Instant.FromUtc(2000, 6, 1, 0, 0).InZone(tz).LocalDateTime);
如果你的本地时区尚未设置为莫斯科,你可以改变的第一行:
DateTimeZone tz = DateTimeZoneProviders.Tzdb["Europe/Moscow"];
OUTPUT:
1/1/2012 4:00:00 AM
6/1/2012 4:00:00 AM
1/1/2000 3:00:00 AM
6/1/2000 4:00:00 AM
更新
AdjustmentRule
上面描述的AdjustmentRule
未跟踪基址偏移量更改的问题在Microsoft支持文章KB3012229中进行了描述,随后在.NET Framework 4.6和.NET Core中进行了修复。
在the reference sources中,可以看到AdjustmentRule
现在保持m_baseUtcOffsetDelta
字段。虽然此字段未通过公共属性公开,但它确实考虑了计算,并且如果您使用FromSerializedString
和ToSerializedString
方法(如果有人实际使用这些方法),它确实会反映在序列化中。
看看'DateTimeOffset'。 ***如果您可以在捕获数据时捕获时区偏移量,则可以更好地显示它并根据它进行计算。 – 2014-10-02 18:18:37