.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