2013-10-17 13 views
9

Ho una situazione in cui mi piacerebbe convertire un DateTime in un Instant. Credo che DateTime 's Kind sarà Local.Come devo convertire un DateTime locale in Instant?

dato che la DateTime è in una variabile chiamata time, la più vicina che ho trovato nella biblioteca è:

Instant.FromDateTimeUtc(time.ToUniversalTime()) 

Questo sembra ragionevole, ma voglio essere certo che questo è completamente affidabile e doesn' t hanno il rischio di perdita o corruzione dei dati. Non sono sicuro se questo è il modo migliore per fare la conversione o se c'è un mezzo più affidabile per farlo.

ho guardato pagina NodaTime BCL Conversions, e ha detto quanto segue su questo scenario:

Nota che non ci sono conversioni ad un DateTime con una sorta di Local - questo sarebbe effettivamente essere per il tempo di default del sistema zona, che in generale dovresti essere esplicito per iniziare.

risposta

16

Ti manca un punto critico: A DateTime il cui tipo è Local non rappresenta sempre un momento unico nel tempo. Questo è il motivo per cui non esiste alcuna mappatura diretta a Instant.

Durante una transizione DST fall-back, un locale DateTime può rappresentare uno dei due possibili momenti nel tempo. Se hai intenzione di convertirlo in un Instant, allora da qualche parte devi decidere quale momento devi scegliere.

Nella risposta che hai dato, sto assumendo si è ottenuto il timezone da uno dei seguenti modi:

var timezone = DateTimeZoneProviders.Tzdb.GetSystemDefault(); 

o

var timezone = DateTimeZoneProviders.Bcl.GetSystemDefault(); 

entrambi sono ok per questo compito. Poi il codice che ha dato:

var localTime = LocalDateTime.FromDateTime(time); 
var zonedTime = localTime.InZoneStrictly(timeZone); 
return zonedTime.ToInstant(); 

Questo è esattamente corretto, ma dal momento che è stato utilizzato InZoneStrictly, si otterrà un AmbiguousTimeException durante la transizione di ripiego.

È possibile evitare questo utilizzando InZoneLeniently, che sceglierà l'ultima delle due possibilità (in genere il tempo "Standard"). Ma ancora più importante, è possibile utilizzare InZone e fornire uno standard resolver personalizzato per controllare il comportamento in modo più preciso.

Per quanto riguarda il suo approccio originale:

Instant.FromDateTimeUtc(time.ToUniversalTime()) 

Questo è ok e non corromperà i dati, ma capire che si baserà sul comportamento del BCL di locali alla conversione universale. È identico a InZoneLeniently, in quanto un valore ambiguo verrà considerato come il tempo "standard".

Questo è un ottimo esempio di come NodaTime offre un'API più precisa. Invece di fare supposizioni, hai l'opportunità di essere specifico e di fornire un comportamento personalizzato. Alla fine hai ottenuto lo stesso risultato, ma ha portato questo problema in primo piano invece di nasconderlo.

+0

Grazie per aver dedicato del tempo per spiegare questo. Penso che questo sarà utile per le altre persone che sono nuove nella biblioteca. – Sam

1

Ho appena realizzato che avrei potuto convertire l'ora locale ad un NodaTimeLocalDateTime e poi mappare ad un istante utilizzando uno dei metodi seguiti da InZoneToInstant. Ecco un esempio supponendo che il fuso orario del tempo sono fornite in timeZone e si desidera un errore essere gettato se il tempo non è valido:

var localTime = LocalDateTime.FromDateTime(time); 
var zonedTime = localTime.InZoneStrictly(timeZone); 
return zonedTime.ToInstant(); 

Tenete a mente che questo è supponendo che time è davvero Local. Se non lo è, credo che il risultato sarà errato.