2014-10-02 103 views
11

我們的政府喜歡更改當地時間或禁用夏令時。
.NET是否有時區更改的歷史記錄?

MS部署的補丁爲俄羅斯考慮新的時間變化。

現在有一個問題,是否存在變化的歷史?

當我在01.01.2000獲得當天的UTC時間時,系統應記住莫斯科時區的UTC爲+3。 (夏季+4)。

對於01.01.2012,我們在冬季和夏季都有+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

看看'DateTimeOffset'。 ***如果您可以在捕獲數據時捕獲時區偏移量,則可以更好地顯示它並根據它進行計算。 – 2014-10-02 18:18:37

回答

4

.NET跟蹤一些的歷史,但它並不總是準確的。你偶然發現了一個不準確的地方。

.NET通過註冊表從Windows導入其所有的時區信息,如herehere所述。如果您在註冊表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字段。雖然此字段未通過公共屬性公開,但它確實考慮了計算,並且如果您使用FromSerializedStringToSerializedString方法(如果有人實際使用這些方法),它確實會反映在序列化中。

+0

幾天前有些事情發生了變化。現在2012年和2013年進口。至少在.NET 4.5.2(Win8.1,Win10)中 1/1/0001 - 12/31/2010 1/1/2011 - 12/31/2011 1/1/2012 - 12/31/2012 1/1/2013 - 12/31/2013 1/1/2014 - 12/31/2014 但2015和2016的數據在哪裏? – 2016-03-02 09:26:56

+0

2014年的最後一次俄羅斯變化減少了夏令時,所以2015年及以後沒有調整規則,因爲沒有調整;偏移是固定的。列表中最後一條規則的最後一個偏移量應該始終適用於該時間。 – 2016-03-02 17:50:56

+0

另外,雖然你的目標是4.5.2,但我猜你已經安裝了4.6,因此它使用[KB3012229]的修補程序(https://support.microsoft.com/en-us/kb/3012229 )在4.6中實現(KB仍需要更新以反映這一點)。副作用是,您現在可以看到2012年和2013年的過渡規則,因爲它現在正確跟蹤基本偏移更改。 – 2016-03-02 17:51:15

2

歷史時間段數據是非常複雜的,充滿了適用的小例外的例子很多在今天沒有簡單描述的特定地理區域。偏移量不僅在變化,而且它們所應用的區域也在變化。

不存在對該數據的歷史,從世界在這裏建模項目:

.NET不支持你想出來的是什麼框。使解決問題的一般解決方案將是非常困難的,但是如果你只需要在一個小區域的集合,那麼你應該能夠填充這個自己使用TimeZoneInfo class,對於該文件規定:

在的TimeZoneInfo類支持的成員如下操作:

  • 創建一個新的時區是不是已經由操作系統定義