2014-10-02 10 views
11

Nasz rząd uwielbia zmieniać czas lokalny lub umożliwić | wyłączenie czasu letniego.
Czy .NET ma historię zmian strefy czasowej?

Wdrożona poprawka MS dla Rosji, aby uwzględnić zmianę czasu.

Teraz pojawia się pytanie, czy historia zmian istnieje?

Kiedy otrzymam czas UTC w dniu 01.01.2000 system powinien pamiętać, że strefa czasowa w Moskwie miała +3 UTC. (w lecie +4) w tym momencie.

Za 01.01.2012 mieliśmy +4 UTC zarówno zimą, jak i latem. I wkrótce będziemy mieli +3 UTC.

proste badanie pokazuje, że .NET nie prowadzi ewidencji o zmianach:

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

Czy istnieją pewne dodatkowe API, aby poradzić sobie z tym problemem?

Aktualizacja:

znalazłeś klasa TimeZoneInfo i pokrewne AdjustmentRule klasa. Pozostało do sprawdzenia, czy dostosowanie strefy czasowej TimeZoneInfo.Local wpływa na interfejsy API DateTime.

Aktualizacja 2: Wygląda UTC offsetu nie są przechowywane jako historii i AdjustmentRule zmiany tylko światło czasu w ciągu roku.

+0

Zobacz "DateTimeOffset". *** Jeśli *** możesz uchwycić przesunięcie strefy czasowej podczas przechwytywania danych, będziesz w lepszym stanie, aby je wyświetlić i obliczyć. –

Odpowiedz

4

.NET utworów niektóre Historia, ale nie zawsze jest dokładne. Natknąłeś się na jedną z nieścisłości.

.NET importuje wszystkie informacje o strefie czasowej z systemu Windows za pośrednictwem rejestru, zgodnie z opisem here i here. Jeśli zajrzysz do rejestru pod numerem HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Time Zones\Russian Standard Time\Dynamic DST, zobaczysz, że śledzone są tylko informacje z 2010 roku dla tej strefy czasowej. Terminy testowania w roku 2000 nie będą się dobrze sprawdzać, ponieważ będą się cofać do najwcześniejszej dostępnej reguły (2010).

Baza przesunięcie UTC informacje jest śledzone w rejestrze, ale niew klasie AdjustmentRule że .NET zaimportowany. Jeśli zaznaczysz zasady regulacji dla tej strefie czasowej, przekonasz się, że 2012 i 2013 nie są importowane w ogóle:

var tz = TimeZoneInfo.FindSystemTimeZoneById("Russian Standard Time"); 
foreach (var rule in tz.GetAdjustmentRules()) 
{ 
    Console.WriteLine("{0:d} - {1:d}", rule.DateStart, rule.DateEnd); 
} 

WYJŚCIE:

1/1/0001 - 12/31/2010 
1/1/2011 - 12/31/2011 
1/1/2014 - 12/31/2014 

Mimo że istnieje w rejestrze systemu Windows, 2012 i 2013 nie są importowane, ponieważ nie mają dostosowań czasu letniego.

Powoduje to problem, gdy zmienia się przesunięcie bazy - tak jak ma to miejsce w tej strefie czasowej. Ponieważ jest to obecnie +3, a dwuletni okres, w którym +4 nie został zaimportowany, to będzie wyglądał tak, jakby wynosił +3 dla brakujących lat.

Nie ma dobrego rozwiązania dla tego przy użyciu TimeZoneInfo. Nawet jeśli spróbujesz stworzyć własne niestandardowe strefy czasowe, będziesz mieć problem z dopasowaniem tego rodzaju zmiany do dostępnych struktur danych.

Na szczęście istnieje inna opcja. Można użyć standardu IANA time zones, korzystając z biblioteki Noda Time.

Poniższy kod wykorzystuje Noda Czas, aby dopasować to, co napisał w swoim oryginalnym kodzie:

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

Jeśli lokalna strefa czasowa nie jest już ustawiony do Moskwy, można zmienić pierwszą linię do:

DateTimeZone tz = DateTimeZoneProviders.Tzdb["Europe/Moscow"]; 

WYJŚCIE:

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 

Aktualizacja

Opisany powyżej problem z AdjustmentRule nie śledzeniem zmian przesunięcia bazy został opisany w artykule pomocy technicznej Microsoft nr KB3012229, a następnie został naprawiony w programie .NET Framework 4.6, a także w .NET Core.

W polu the reference sources widać, że AdjustmentRule przechowuje teraz pole m_baseUtcOffsetDelta. Chociaż to pole nie jest wyeksponowane przez właściwość publiczną, bierze pod uwagę obliczenia i odzwierciedla serializację, jeśli stosujesz metody FromSerializedString i ToSerializedString (jeśli ktokolwiek faktycznie je wykorzystuje).

+0

Coś się zmieniło kilka dni temu. Teraz 2012 i 2013 są importowane. Przynajmniej w .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 - 31.12.2013 01.01.2014 - 31.12.2014 Ale gdzie są dane na 2015 i 2016 rok? –

+0

Ostatnia zmiana w Rosji w 2014 roku skróciła czas letni, więc nie ma żadnych zasad dostosowawczych na rok 2015 i późniejsze, ponieważ nie ma żadnych korekt; przesunięcie jest stałe. Ostatnie przesunięcie ostatniej reguły na liście powinno zawsze obowiązywać od tego czasu. –

+0

Ponadto, mimo że kierujesz reklamy do wersji 4.5.2, domyślam się, że masz zainstalowaną wersję 4.6, więc używa ona poprawki dla [KB3012229] (https://support.microsoft.com/en-us/kb/3012229), który został wdrożony w wersji 4.6 (KB musi zostać zaktualizowany, aby to odzwierciedlić). Efektem ubocznym jest to, że teraz widzisz reguły przejścia na 2012 i 2013, ponieważ teraz poprawnie śledzą zmiany offsetów bazowych. –

2

Dane historyczne strefa czasowa jest bardzo skomplikowane i pełne wielu przykładów małymi wyjątkami, które stosują w określonych regionach geograficznych, które dziś nie są łatwe do opisania. Nie tylko zmieniają się przesunięcia, ale także regiony, w których są stosowane.

Jest projekt modelować historię tych danych z całego świata tutaj:

.NET nie obsługuje, co chcesz z pudełko.Dokonywanie ogólne rozwiązanie problemu będzie bardzo trudne, ale jeśli tylko trzeba go nad małym zestawem regionach, to powinieneś być w stanie wypełnić ten sam Używanie TimeZoneInfo class dokumentacja dla których stwierdza:

członkowie wsparciu klasy TimeZoneInfo następujące operacje:

  • Tworzenie nowej strefy czasowej, która nie jest już zdefiniowane przez system operacyjny