Convertire ora UTC / GMT in ora locale

Stiamo sviluppando un’applicazione C # per un client di servizi Web. Questo verrà eseguito su PC Windows XP.

Uno dei campi restituiti dal servizio Web è un campo DateTime. Il server restituisce un campo in formato GMT cioè con una “Z” alla fine.

Tuttavia, abbiamo scoperto che .NET sembra fare una specie di conversione implicita e il tempo è sempre stato di 12 ore.

Il seguente esempio di codice risolve questo problema in quanto la differenza di 12 ore è passata, ma non tiene conto dell’ora legale in NZ.

CultureInfo ci = new CultureInfo("en-NZ"); string date = "Web service date".ToString("R", ci); DateTime convertedDate = DateTime.Parse(date); 

Come da questo sito data :

Offset UTC / GMT

Fuso orario standard: UTC / GMT +12 ore
Ora legale: +1 ora
Offset fuso orario corrente: UTC / GMT +13 ore

Come possiamo aggiustare per l’ora in più? Può essere fatto a livello di programmazione o è una sorta di impostazione sul PC?

Per stringhe come 2012-09-19 01:27:30.000 , DateTime.Parse non può indicare da che fuso orario sono la data e l’ora.

DateTime ha una proprietà Kind , che può avere una delle tre opzioni di fuso orario:

  • imprecisato
  • Locale
  • UTC

NOTA Se si desidera rappresentare una data / ora diversa da UTC o il fuso orario locale, utilizzare DateTimeOffset .


Quindi per il codice nella tua domanda:

 DateTime convertedDate = DateTime.Parse(dateStr); var kind = convertedDate.Kind; // will equal DateTimeKind.Unspecified 

Dici di sapere di che tipo si tratta, quindi dillo.

 DateTime convertedDate = DateTime.SpecifyKind( DateTime.Parse(dateStr), DateTimeKind.Utc); var kind = convertedDate.Kind; // will equal DateTimeKind.Utc 

Ora, una volta che il sistema è a conoscenza dell’ora UTC, puoi chiamare ToLocalTime :

 DateTime dt = convertedDate.ToLocalTime(); 

Questo ti darà il risultato che desideri.

Vorrei esaminare l’utilizzo della class System.TimeZoneInfo se si è in .NET 3.5. Vedi http://msdn.microsoft.com/en-us/library/system.timezoneinfo.aspx . Questo dovrebbe tenere conto delle modifiche dell’ora legale correttamente.

 // Coordinated Universal Time string from // DateTime.Now.ToUniversalTime().ToString("u"); string date = "2009-02-25 16:13:00Z"; // Local .NET timeZone. DateTime localDateTime = DateTime.Parse(date); DateTime utcDateTime = localDateTime.ToUniversalTime(); // ID from: // "HKEY_LOCAL_MACHINE\Software\Microsoft\Windows NT\CurrentVersion\Time Zone" // See http://msdn.microsoft.com/en-us/library/system.timezoneinfo.id.aspx string nzTimeZoneKey = "New Zealand Standard Time"; TimeZoneInfo nzTimeZone = TimeZoneInfo.FindSystemTimeZoneById(nzTimeZoneKey); DateTime nzDateTime = TimeZoneInfo.ConvertTimeFromUtc(utcDateTime, nzTimeZone); 
 TimeZone.CurrentTimeZone.ToLocalTime(date); 

DateTime oggetti DateTime hanno il Kind di Unspecified per impostazione predefinita, che per gli scopi di ToLocalTime è considerato UTC .

Per ottenere l’ora locale di un object DateTime Unspecified , è quindi sufficiente effettuare questa operazione:

 convertedDate.ToLocalTime(); 

La procedura per modificare il Kind di DateTime da Unspecified a UTC non è necessaria. Si presuppone che non specificato UTC per gli scopi di ToLocalTime : http://msdn.microsoft.com/en-us/library/system.datetime.tolocaltime.aspx

So che questa è una domanda più vecchia, ma mi sono imbattuto in una situazione simile e volevo condividere ciò che avevo trovato per i futuri utenti, possibilmente incluso me stesso :).

DateTime.Parse() può essere difficile – vedi qui per esempio.

Se DateTime proviene da un servizio Web o da un’altra fonte con un formato noto, potresti prendere in considerazione qualcosa di simile

 DateTime.ParseExact(dateString, "MM/dd/yyyy HH:mm:ss", CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal | DateTimeStyles.AdjustToUniversal) 

o, ancora meglio,

 DateTime.TryParseExact(...) 

Il flag AssumeUniversal dice al parser che la data / ora è già UTC; la combinazione di AssumeUniversal e AdjustToUniversal dice di non convertire il risultato in tempo “locale”, che proverà a fare di default. (Personalmente, cerco di trattare esclusivamente con UTC nel / i livello / i di applicazione / servizio / i di servizio, ma bypassare la conversione in ora locale accelera anche le cose – del 50% o più nei miei test, vedi sotto).

Ecco cosa stavamo facendo prima:

 DateTime.Parse(dateString, new CultureInfo("en-US")) 

Avevamo analizzato l’app e scoperto che DateTime.Parse rappresentava una percentuale significativa dell’utilizzo della CPU. (Per inciso, il costruttore di CultureInfo non ha contribuito in maniera significativa all’utilizzo della CPU.)

Così ho configurato un’app per console per analizzare una stringa data / ora 10000 volte in vari modi. Linea di fondo:
Parse() 10 sec
ParseExact() (conversione in locale) 20-45 ms
ParseExact() (non convertito in locale) 10-15 ms
… e sì, i risultati per Parse() sono Parse() in secondi , mentre gli altri sono in millisecondi .

Vorrei solo aggiungere una nota generale di caucanvas.

Se tutto quello che stai facendo è ottenere l’ora corrente dall’orologio interno del computer per inserire una data / un’ora sul display o su un rapporto, allora va tutto bene. Ma se stai salvando le informazioni su data / ora per riferimento futuro o stai calcolando data / ora, fai attenzione!

Supponiamo che tu determini che una nave da crociera è arrivata a Honolulu il 20 dicembre 2007 alle 15:00 UTC. E tu vuoi sapere che ora locale era.
1. Ci sono probabilmente almeno tre “locali” coinvolti. Locale può significare Honolulu, o può significare dove si trova il tuo computer, o può significare la posizione in cui si trova il tuo cliente.
2. Se si utilizzano le funzioni integrate per eseguire la conversione, probabilmente sarà sbagliato. Questo perché l’ora legale è (probabilmente) attualmente in vigore sul tuo computer, ma NON era in vigore a dicembre. Ma Windows non lo sa … tutto quello che ha è una bandiera per determinare se l’ora legale è attualmente in vigore. E se è attualmente in vigore, aggiungerà felicemente un’ora anche a una data di dicembre.
3. L’ ora legale è implementata in modo diverso (o non lo è affatto) in varie suddivisioni politiche. Non pensare che solo perché il tuo paese cambia in una data specifica, anche gli altri paesi lo faranno.

Non dimenticare che se hai già un object DateTime e non sei sicuro se è UTC o Local, è abbastanza facile usare direttamente i metodi sull’object:

 DateTime convertedDate = DateTime.Parse(date); DateTime localDate = convertedDate.ToLocalTime(); 

Come possiamo aggiustare per l’ora in più?

A meno che specificato .net utilizzerà le impostazioni del pc locale. Avrei letto di: http://msdn.microsoft.com/en-us/library/system.globalization.daylighttime.aspx

Dagli sguardi il codice potrebbe sembrare qualcosa di simile:

 DaylightTime daylight = TimeZone.CurrentTimeZone.GetDaylightChanges( year ); 

E come sopra menzionato, verifica in base a quale fuso orario il tuo server è acceso. Esistono articoli in rete su come influire in modo sicuro sulle modifiche in IIS.

In risposta al suggerimento di Dana:

L’esempio del codice ora sembra:

 string date = "Web service date"..ToString("R", ci); DateTime convertedDate = DateTime.Parse(date); DateTime dt = TimeZone.CurrentTimeZone.ToLocalTime(convertedDate); 

La data originale era il 20/08/08; il tipo era UTC.

Sia “convertito” che “dt” sono gli stessi:

21/08/08 10:00:26; il tipo era locale

Ho avuto il problema di trovarsi in un set di dati spinto attraverso il filo (webservice al client) che cambierebbe automaticamente perché il campo DateType del DataColumn era impostato su locale. Assicurati di controllare cosa è il DateType se si spinge DataSet attraverso.

Se non vuoi che cambi, impostalo su Non specificato

Mi sono imbattuto in questa domanda perché avevo un problema con le date UTC che si ricevono tramite l’API di Twitter (campo created_at su uno stato); Devo convertirli in DateTime. Nessuna delle risposte / esempi di codice nelle risposte in questa pagina è stata sufficiente per impedirmi di ricevere un errore “String non è stato riconosciuto come un DateTime valido” (ma è il più vicino che ho trovato per trovare la risposta corretta su SO)

Pubblicare questo link qui nel caso in cui questo aiuti qualcun altro – la risposta che cercavo è stata trovata su questo post del blog: http://www.wduffy.co.uk/blog/parsing-dates-when-aspnets-datetimeparse-doesnt-work/ – Fondamentalmente usa DateTime.ParseExact con una stringa di formato invece di DateTime.Parse

 @TimeZoneInfo.ConvertTimeFromUtc(timeUtc, TimeZoneInfo.Local)