我们的政府喜欢改变当地时间或禁用夏令时。
MS为俄罗斯部署补丁以考虑新的时间变化。
现在是否存在变更历史的问题?
当我在01.01.2000系统获得当天的UTC时间时,系统应记住莫斯科时区的时间为+3 UTC。 (在夏天+4)那一刻。
2012年1月1日,我们在冬季和夏季都有+4 UTC。很快我们将有+3 UTC。
简单测试表明.NET没有保留有关更改的记录:
var t = new DateTime(2012,1,1);
// UTC +4 expected
System.Console.WriteLine(t.ToLocalTime());
// UTC +4 expected
t = new DateTime(2012,06,1);
System.Console.WriteLine(t.ToLocalTime());
// UTC +3 expected
t = new DateTime(2000,1,1);
System.Console.WriteLine(t.ToLocalTime());
// UTC +4 expected
t = new DateTime(2000,6,1);
System.Console.WriteLine(t.ToLocalTime());
是否存在一些额外的API来解决问题?
更新
找到了课程TimeZoneInfo和相关的AdjustmentRule课程。留下来测试TimeZoneInfo.Local
时区的自定义是否会影响DateTime API。
更新2:
似乎UTC偏移量不会存储为历史记录,而AdjustmentRule
仅会更改一年中的白天时间。
答案 0 :(得分:7)
.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);
}
输出:
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。
以下代码使用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"];
输出:
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
未跟踪基本偏移量更改的问题在Microsoft支持文章KB3012229中有所描述,随后在.NET Framework 4.6和.NET Core中进行了修复。
在the reference sources中,可以看到AdjustmentRule
现在保留m_baseUtcOffsetDelta
字段。虽然此字段不是通过公共属性公开的,但它确实考虑了计算,如果您使用FromSerializedString
和ToSerializedString
方法(如果有人实际使用这些方法),它确实反映在序列化中。< / p>
答案 1 :(得分:2)
答案 2 :(得分:2)
历史时区数据非常复杂,并且填充了许多适用于特定地理区域的小例外情况的例子,这些例外目前没有简单的描述方式。不仅偏移在变化,而且它们应用的区域也在变化。
有一个项目来模拟来自世界各地的这些数据的历史记录:
.NET不支持开箱即用的功能。对问题进行一般性解决方案将非常困难,但是如果您只需要在一小部分区域内进行解决,那么您应该能够使用TimeZoneInfo
class自己填充这个,这些文档的状态为:
TimeZoneInfo类的成员支持以下操作:
- 创建尚未由操作系统定义的新时区