Pav*_*nin 18 .net timezone datetime
我们的政府喜欢改变当地时间或启用夏令时.
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());
Run Code Online (Sandbox Code Playgroud)
是否存在一些额外的API来应对这个问题?
更新:
找到了类TimeZoneInfo和相关的AdjustmentRule类.留下来测试TimeZoneInfo.Local
时区的自定义是否会影响DateTime API.
更新2:
似乎UTC偏移不会存储为历史记录,AdjustmentRule
只会更改一年中的白天时间.
.NET跟踪一些历史记录,但是它并不总是准确的。您偶然发现了其中一种错误。
.NET通过注册表从Windows导入所有时区信息,如此处和此处所述。如果您查看注册表,HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Time Zones\Russian Standard Time\Dynamic DST
则会发现它仅跟踪该时区从2010年开始的信息。2000年的测试日期不能很好地起作用,因为它将追溯到最早的可用规则(2010年)。
基地UTC偏移信息被跟踪在注册表中,而不是在AdjustmentRule
类.NET进口成。如果查看此时区的调整规则,则会发现根本没有导入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);
}
Run Code Online (Sandbox Code Playgroud)
输出:
var tz = TimeZoneInfo.FindSystemTimeZoneById("Russian Standard Time");
foreach (var rule in tz.GetAdjustmentRules())
{
Console.WriteLine("{0:d} - {1:d}", rule.DateStart, rule.DateEnd);
}
Run Code Online (Sandbox Code Playgroud)
即使Windows注册表中存在它们,也不会导入2012和2013,因为它们没有夏令时调整。
当基本偏移量更改时,这会产生问题-就像该时区一样。由于当前为+3,并且未输入原为+4的两年,因此对于那些缺失的年份,它看起来像为+3。
使用此方法没有好的解决方案TimeZoneInfo
。即使您尝试创建自己的自定义时区,也很难将这种变化适合可用的数据结构。
幸运的是,还有另一种选择。您可以通过Noda Time库使用标准的IANA时区。
以下代码使用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);
Run Code Online (Sandbox Code Playgroud)
如果尚未为莫斯科设置本地时区,则可以将第一行更改为:
DateTimeZone tz = DateTimeZoneProviders.Tzdb["Europe/Moscow"];
Run Code Online (Sandbox Code Playgroud)
输出:
1/1/0001 - 12/31/2010
1/1/2011 - 12/31/2011
1/1/2014 - 12/31/2014
Run Code Online (Sandbox Code Playgroud)
AdjustmentRule
Microsoft支持文章KB3012229中描述了上述不跟踪基本偏移量更改的问题,随后在.NET Framework 4.6和.NET Core中修复了该问题。
在参考资料中,可以看到AdjustmentRule
现在保留了一个m_baseUtcOffsetDelta
字段。尽管此字段不是通过公共属性公开的,但它确实会影响计算,并且如果您使用FromSerializedString
and ToSerializedString
方法(如果有人实际使用那些方法),它的确会反映在序列化中。
归档时间: |
|
查看次数: |
1680 次 |
最近记录: |