2014-10-02 6 views
11

Il nostro governo ama modificare l'ora locale o abilitare | disabilitare l'ora legale.
.NET ha la cronologia delle modifiche del fuso orario?

MS ha distribuito una patch per la Russia affinché tenga conto del nuovo cambiamento di orario.

Ora c'è la domanda se la cronologia delle modifiche esiste?

Quando ottengo l'ora UTC del giorno in 01.01.2000 il sistema dovrebbe ricordare che il fuso orario di Mosca ha +3 UTC. (in estate +4) in quel momento.

Per 01.01.2012 abbiamo avuto +4 UTC sia per l'inverno che per l'estate. E presto avremo +3 UTC.

semplice test mostra che .NET non tenere un registro dei cambiamenti:

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

fa alcune API aggiuntive esistono per affrontare il problema?

Aggiornamento:

hanno trovato classe TimeZoneInfo e relativo AdjustmentRule di classe. Lasciato a testare se la personalizzazione del fuso orario TimeZoneInfo.Local influenza le API DateTime.

Aggiornamento 2: Sembra come offset UTC non vengono memorizzati come storia e AdjustmentRule modifiche solo il tempo la luce del giorno durante l'anno.

+0

Dai un'occhiata a "DateTimeOffset'. *** Se *** puoi catturare l'offset del fuso orario mentre acquisisci i dati sarai più in forma per visualizzarli e calcolare contro di essi. –

risposta

4

NET tracce della cronologia, ma non è sempre preciso. Sei incappato in una delle inesattezze.

.NET importa tutte le informazioni sul fuso orario da Windows tramite il registro, come descritto here e here. Se si guarda nel registro HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Time Zones\Russian Standard Time\Dynamic DST, si scoprirà che tiene traccia solo delle informazioni dal 2010 in avanti per questo fuso orario. Le date dei test nell'anno 2000 non funzioneranno bene, poiché ricadranno nella prima regola disponibile (2010).

Base UTC compensata informazioni è rintracciato nel Registro di sistema, ma non nella classe AdjustmentRule che .NET importa in. Se si controlla le regole di regolazione per questo fuso orario, troverete che il 2012 e il 2013 non vengono importate a tutti:

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

USCITA:

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

Anche se esistono nel Registro di sistema di Windows, 2012 e 2013 non vengono importati perché non hanno regolazioni dell'ora legale.

Questo crea un problema quando lo scostamento di base cambia, come nel caso di questo fuso orario. Dal momento che è attualmente +3, e il due anni in cui era +4 non sono stati importati, sembrerà che sia stato +3 per gli anni mancanti.

Non c'è una buona soluzione per questo utilizzando TimeZoneInfo. Anche se provi a creare i tuoi fusi orari personalizzati, avrai difficoltà ad inserire questo tipo di cambiamento nelle strutture dati disponibili.

Fortunatamente, c'è un'altra opzione. È possibile utilizzare lo standard IANA time zones tramite la libreria Noda Time.

Il codice seguente utilizza Noda tempo per abbinare quello che hai scritto nel codice originale:

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

Se il fuso orario locale non è già impostato per Mosca, è possibile cambiare la prima linea a:

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

USCITA:

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 

Aggiornamento

0.123.516,410617 millions

Il problema descritto sopra di AdjustmentRule che non rileva le variazioni di offset di base è stato descritto nell'articolo di supporto Microsoft KB3012229 e successivamente risolto in .NET Framework 4.6 e anche in .NET Core.

In the reference sources, si può vedere che AdjustmentRule ora mantiene un campo m_baseUtcOffsetDelta. Anche se questo campo non è esposto tramite una proprietà pubblica, esso fa riferimento ai calcoli e riflette nella serializzazione se si utilizzano i metodi FromSerializedString e ToSerializedString (se qualcuno li utilizza effettivamente).

+0

Qualcosa è cambiato un paio di giorni fa. Ora 2012 e 2013 sono importati. Almeno in .NET 4.5.2 (Win8.1, Win10) 011/0001 - 31/12/2010 1/1/2011 - 31/12/2011 1/1/2012 - 12/31/2012 1/1/2013 - 31/12/2013 1/1/2014 - 31/12/2014 Ma dove sono i dati per 2015 e 2016? –

+0

L'ultima modifica della Russia nel 2014 è caduta all'ora legale, quindi non ci sono regole di adeguamento per il 2015 e successive perché non ci sono aggiustamenti; l'offset è fisso. L'ultimo offset dell'ultima regola nell'elenco dovrebbe sempre essere applicato da quel momento. –

+0

Inoltre, anche se il tuo targeting è 4.5.2, suppongo che tu abbia 4.6 installato sulla scatola, quindi sta utilizzando la correzione per [KB3012229] (https://support.microsoft.com/en-us/kb/3012229) che è stato implementato in 4.6 (il KB deve ancora essere aggiornato per riflettere questo). L'effetto collaterale è che ora vedi le regole di transizione per il 2012 e il 2013 perché ora sta monitorando correttamente le modifiche alla base offset. –

2

dati in tempo storico Località è molto complesso e pieno di molti esempi di piccole eccezioni che si applicano in specifiche regioni geografiche che oggi non hanno un modo facile di essere descritte. Non solo gli offset cambiano, ma lo sono anche le regioni in cui vengono applicati.

C'è un progetto per modellare la storia di questi dati da tutto il mondo qui:

.NET non supporta ciò che si desidera fuori dal scatola.Fare una soluzione generale al problema sarà molto difficile, ma se avete solo bisogno sopra un piccolo insieme di regioni, allora si dovrebbe essere in grado di compilare da soli utilizzando il TimeZoneInfo class, la documentazione per la quale afferma:

i membri della classe sostegno TimeZoneInfo le seguenti operazioni:

  • Creazione di un nuovo fuso orario che non sia già definite dal sistema operativo