2014-10-02 6 views
11

Unsere Regierung liebt es, die Ortszeit zu ändern oder die Sommerzeit zu deaktivieren.
Hat .NET die Geschichte von Zeitzonenänderungen?

MS-Patch für Russland eingeführt, um neue Zeit zu berücksichtigen.

Jetzt ist die Frage, ob die Geschichte der Änderungen existiert?

Wenn ich UTC Uhrzeit des Tages in 01.01.2000 System sollte beachten, dass Moskau Zeitzone +3 UTC hatte. (im Sommer +4) in diesem Moment.

Zum 01.01.2012 hatten wir +4 UTC für Winter und Sommer. Und bald werden wir +3 UTC haben.

einfacher Test zeigt, dass .NET nicht halten Aufzeichnungen über die Änderungen:

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()); 

Hat einige zusätzliche API mit dem Problem fertig zu werden gibt es?

Update:

gefunden Klasse TimeZoneInfo und zugehörige AdjustmentRule Klasse. Links, um zu testen, ob die Anpassung der Zeitzone "TimeZoneInfo.Local" Auswirkungen auf DateTime-APIs hat.

Update 2: Scheinen, wie UTC Offsets werden nicht als Geschichte und AdjustmentRule Änderungen nur Sommerzeit im Laufe des Jahres gespeichert.

+0

Werfen Sie einen Blick auf 'DateTimeOffset'. *** Wenn *** Sie den Zeitzonen-Offset erfassen können, während Sie die Daten erfassen, sind Sie besser in der Lage, sie anzuzeigen und dagegen zu berechnen. –

Antwort

4

.NET definiert ist Spuren einige Geschichte, aber es ist nicht immer genau. Sie sind auf eine der Ungenauigkeiten gestoßen.

.NET importiert alle Zeitzoneninformationen von Windows über die Registrierung, wie beschrieben here und here. Wenn Sie in der Registrierung unter HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Time Zones\Russian Standard Time\Dynamic DST suchen, werden Sie feststellen, dass nur Informationen von 2010 für diese Zeitzone nachverfolgt werden. Die Testdaten im Jahr 2000 werden nicht gut funktionieren, da sie auf die früheste verfügbare Regel (2010) zurückgehen werden.

Basis UTC Offset-Informationen in der Registrierung verfolgt, aber nicht in der AdjustmentRule Klasse, die .NET es in importiert. Wenn Sie die Anpassungsregeln für diese Zeitzone überprüfen, werden Sie feststellen, dass 2012 und 2013 werden nicht importiert:

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 

Auch wenn sie in der Windows-Registrierung vorhanden ist, 2012 und 2013 werden nicht importiert, da sie keine Sommerzeiteinstellungen haben.

Dies erzeugt ein Problem, wenn sich der Basisoffset ändert - wie für diese Zeitzone. Da es derzeit +3 ist und die zwei Jahre, in denen es +4 war, nicht importiert wurden, wird es für die fehlenden Jahre wie +3 aussehen.

Es gibt keine gute Lösung dafür mit TimeZoneInfo. Selbst wenn Sie versuchen, Ihre eigenen benutzerdefinierten Zeitzonen zu erstellen, werden Sie Schwierigkeiten haben, diese Art von Änderung in die verfügbaren Datenstrukturen einzubauen.

Zum Glück gibt es eine andere Option. Sie können den Standard IANA time zones über die Bibliothek Noda Time verwenden.

Der folgende Code verwendet Noda Zeit zu entsprechen, was Sie in Ihrem ursprünglichen Code geschrieben haben:

:

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); 

Wenn Ihre lokale Zeitzone nicht bereits für Moskau eingestellt ist, können Sie die erste Zeile ändern

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 

aktualisieren

Das oben beschriebene Problem von AdjustmentRule Verfolgen Base Offset-Änderungen wurde in Microsoft Support-Artikel KB3012229 beschrieben und anschließend in .NET Framework 4.6 und .NET Core behoben.

In the reference sources kann man sehen, dass AdjustmentRule jetzt ein m_baseUtcOffsetDelta Feld hält. Obwohl dieses Feld nicht über eine öffentliche Eigenschaft verfügbar gemacht wird, spielt es bei den Berechnungen eine Rolle, und es spiegelt sich in der Serialisierung wider, wenn Sie die Methoden FromSerializedString und ToSerializedString verwenden (falls tatsächlich jemand diese verwendet).

+0

Etwas hat sich vor ein paar Tagen geändert. Jetzt werden 2012 und 2013 importiert. Zumindest in .NET 4.5.2 (Win8.1, Win10) 1/1/0001 - 31.12.2010 01.01.2011 - 31.12.2011 01.01.2012 - 31.12/2012 1/1/2013 - 31.12.2013 01.01.2014 - 31.12.2014 Aber wo sind die Daten für 2015 und 2016? –

+0

Die letzte Änderung in Russland im Jahr 2014 hat die Sommerzeit reduziert, daher gibt es keine Anpassungsregeln für 2015 und später, da keine Anpassungen vorgenommen wurden. Der Offset ist festgelegt. Der letzte Offset der letzten Regel in der Liste sollte immer ab diesem Zeitpunkt gelten. –

+0

Auch wenn Sie auf 4.5.2 abzielen, rate ich, dass Sie 4.6 auf der Box installiert haben, damit das Update für [KB3012229] (https://support.microsoft.com/en-us/kb/3012229), die in 4.6 implementiert wurde (die KB muss noch aktualisiert werden, um dies zu berücksichtigen). Der Nebeneffekt ist, dass Sie nun die Übergangsregeln für 2012 und 2013 sehen, da Änderungen am Basisoffset jetzt korrekt verfolgt werden. –

2

Historische Zeitzonendaten sehr komplex und mit vielen Beispielen von kleinen Ausnahmen gefüllt, die gelten, in bestimmten geografischen Regionen, die heute nicht einfach beschrieben werden können. Nicht nur die Offsets ändern sich, sondern auch die Regionen, auf die sie angewendet werden.

Es ist ein Projekt, die Geschichte dieser Daten zu modellieren aus der ganzen Welt hier:

.NET nicht unterstützt, was Sie aus der wollen Box.eine allgemeine Lösung des Problems machen wird sehr schwierig sein, aber wenn Sie es über einen kleinen Satz von Regionen benötigen, dann sollten Sie in der Lage sein, dies selbst mit dem TimeZoneInfo class zu füllen, die Dokumentation zu dem es heißt:

die Mitglieder der Klasse Timezone unterstützt die folgenden Operationen:

  • eine neue Zeitzone erstellen, die nicht bereits durch das Betriebssystem
Verwandte Themen