.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).
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).
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ć. –