2013-05-01 28 views
9

Abbiamo riscontrato un problema in cui uno sviluppatore crea il codice seguente e funziona nel proprio ambiente DEV. Ma quando è controllato in QA, il codice rompe con il seguente messaggio di errore:TimeZoneInfo.ConvertTimeToUtc issue

myRecord.UTCStartTime = TimeZoneInfo.ConvertTimeToUtc(myRecord.StartTime, myTimeZone); 

La conversione non è stato possibile completare in quanto la dotazione DateTime non ha avuto la proprietà Kind impostato correttamente. Ad esempio, quando la proprietà Tipo è DateTimeKind.Local, il fuso orario dell'origine deve essere TimeZoneInfo.Local.

Nell'ambiente DEV, il codice sopra riportato genera lo stesso errore del server QA. Ho applicato il cambio di seguito per risolvere il problema:

DateTime utcStart = DateTime.SpecifyKind(myRecord.StartTime, DateTimeKind.Unspecified); 
myRecord.UTCStartTime = TimeZoneInfo.ConvertTimeToUtc(utcStart, myTimeZone); 

Perché il primo codice di esempio il lavoro sull'ambiente DEV1 ma rompere il mio ambiente dev e sul nostro server di QA?

risposta

30

Dipende da come è stato originato myRecord.StartTime.

  • Se lo avete ottenuto da DateTime.Now, allora avrà un tipo Local.
  • Se l'hai preso da DateTime.UtcNow allora avrà un tipo Utc.
  • Se lo avete preso da new DateTime(2013,5,1) allora avrà un tipo Unspecified.

Dipende anche da dove si è ottenuto myTimeZone da. Per esempio:

  • TimeZoneInfo.Local
  • TimeZoneInfo.Utc
  • TimeZoneInfo.FindSystemTimeZoneById("Central Standard Time")

La funzione TimeZoneInfo.ConvertTimeToUtc funziona solo se si può abbinare la zona per il tipo che si dà. Se entrambi sono locali o entrambi sono UTC, funzionerà. Se le stai assegnando una zona specifica, il tipo dovrebbe essere non specificato. Questo comportamento è documented on MSDN.

Si può facilmente riprodurre l'eccezione in modo coerente:

var tz = TimeZoneInfo.FindSystemTimeZoneById("Fiji Standard Time"); 
var utc = TimeZoneInfo.ConvertTimeToUtc(DateTime.Now, tz); 

Dando per scontato che non si vive nelle isole Figi, questo errore ogni volta. In pratica hai detto "converti il ​​mio fuso orario locale, in qualche altra zona, a utc", il che non ha senso.

Probabilmente funziona nell'ambiente di sviluppo perché il valore che si sta verificando per myTimeZone è la zona locale per lo sviluppatore.

Per quanto riguarda il tuo cambiamento, puoi forzare il tipo a non essere specificato e questo cambia il significato di ciò che stai facendo in modo che abbia senso. Ma sei sicuro che questo è quello che vuoi? Qual è il .Kind della data prima mano? Se non è già Unspecified, allora sta portando un po 'di intento. Probabilmente dovresti tornare alla fonte di questi dati e assicurarti che sia quello che ti aspetti.

Se tutto ciò suona pazzo, pazzo, frustrante e bizzarro, è perché l'oggetto DateTime puzza. Ecco qualche lettura supplementare:

Si potrebbe considerare l'utilizzo di NodaTime invece. La sua API ti impedirà di fare questi tipi di errori comuni.

1

in questo esempio ho convertito il fuso orario di tipo non specificato in modo che funziona bene per me usando "DateTime.SpecifyKind()" metodo

DateTime.SpecifyKind (UTC, DateTimeKind.Unspecified);

questo metodo Crea un nuovo oggetto DateTime che ha lo stesso numero di zecche del DateTime specificato, ma è designato come tipo non specificato di DateTimeKind.

public static DateTime ConvertLocalDate (DateTime UTC) {

 string id = ConfigurationManager.AppSettings["Timezone"].ToString(); 
     TimeZoneInfo cstZone = TimeZoneInfo.FindSystemTimeZoneById(id); 
     utc = DateTime.SpecifyKind(utc,DateTimeKind.Unspecified); 
     DateTime cstTime = TimeZoneInfo.ConvertTimeFromUtc(utc, cstZone); 
     return cstTime; 
    } 
1

ho trovato davvero una soluzione semplice qui https://kiranpatils.wordpress.com/2011/01/09/the-conversion-could-not-be-completed-because-the-supplied-datetime-did-not-have-the-kind-property-set-correctly-for-example-when-the-kind-property-is-datetimekind-local-the-source-time-zone-must/

che appare solo per accadere quando si utilizza DateTime.Now . Aggiorna il mio codice come segue e funziona di nuovo :)

DateTime currentTime = new DateTime (DateTime.Now.Ticks, DateTimeKind.Unspecified);

1

uso Datetime.SpecifyKind:

var localDateTime = DateTime.SpecifyKind(localDate, DateTimeKind.Unspecified); 

var utcDateTime = TimeZoneInfo.ConvertTimeToUtc(localDateTime, timeZoneId); 
+0

Non hai risposto alla domanda - "Perché il primo codice di esempio il lavoro sull'ambiente DEV1 ma rompere il mio ambiente dev e sul nostro server QA?" – Enigmativity

+0

Questo codice è la stessa soluzione menzionata nella domanda stessa. – BACON