Come utilizzare TimeZoneInfo per ottenere l'ora locale durante l'ora legale?


85

Sto cercando di utilizzare DateTimeOffsetper trasmettere un momento specifico nel tempo in qualsiasi fuso orario. Non riesco a capire come utilizzare TimeZoneInfoper affrontare l'ora legale.

var dt = DateTime.UtcNow;
Console.WriteLine(dt.ToLocalTime());

var tz = TimeZoneInfo.FindSystemTimeZoneById("Central Standard Time");
var utcOffset = new DateTimeOffset(dt, TimeSpan.Zero);
Console.WriteLine(utcOffset.ToOffset(tz.BaseUtcOffset));

Questo stampa:

6/2/2010 16:37:19
6/2/2010 3:37:19 PM -06: 00

Mi trovo nel fuso orario centrale e attualmente siamo all'ora legale. Sto cercando di leggere la seconda riga:

6/2/2010 4:37:19 PM -05: 00

BaseUtcOffset apparentemente non cambia in base all'ora legale.

Come posso ottenere il momento giusto con il valore di offset corretto?


13
+1 - mi fa impazzire che TimeZoneInfo.ConvertTimeBySystemTimeZoneId non funzioni solo per questo :)
James Manning

@JamesManning - Sì, supponendo che dt.Kindsia impostato correttamente.
Matt Johnson-Pint

Risposte:


63

È necessario ottenere UtcOffset da TimeZoneInfo, quindi passarlo al metodo ToOffset ():

var dt = DateTime.UtcNow;
Console.WriteLine(dt.ToLocalTime());

var tz = TimeZoneInfo.FindSystemTimeZoneById("Central Standard Time");
var utcOffset = new DateTimeOffset(dt, TimeSpan.Zero);
Console.WriteLine(utcOffset.ToOffset(tz.GetUtcOffset(utcOffset)));

capisco ... devi ottenere l'offset UTC per quella data specifica nel fuso orario. Grazie.
jaminto

6
Questo non è il modo migliore rispetto alla risposta di Karl Gjertsen che utilizza una singola funzione .Net per eseguire il lavoro invece di estrarre l'offset creando un nuovo, usa e getta DateTimeOffset.
ErikE

60

Puoi anche utilizzare TimeZoneInfo.ConvertTimeFromUtc, che consentirà l'ora legale:

DateTime utc = DateTime.UtcNow;
TimeZoneInfo zone = TimeZoneInfo.FindSystemTimeZoneById("Central Standard Time");
DateTime localDateTime = TimeZoneInfo.ConvertTimeFromUtc(utc, zone);

E se il fuso orario del mio paese è EEST in estate e EET in inverno? Come funzionerebbe con l'ora legale?
Rami Zebian

1
Windows conosce le informazioni sul fuso orario, insieme alle date dell'ora legale. Dovrebbe funzionare o tu se scegli uno dei fusi orari predefiniti.
Karl Gjertsen

11

O meglio, se non vuoi codificare l' identificatore del fuso orario :

TimeZoneInfo tzi = TimeZoneInfo.FindSystemTimeZoneById(TimeZoneInfo.Local.Id);
DateTime localDateTime = TimeZoneInfo.ConvertTimeFromUtc(DateTime.UtcNow, tzi);

2
Non potresti semplicemente usare TimeZoneInfo.Localdirettamente? Perché hai bisogno della chiamata a FindSystemTimeZoneById?
CoderDennis

4
Hai ragione, non ne abbiamo bisogno. Possiamo farlo in questo modoDateTime localDateTime = TimeZoneInfo.ConvertTimeFromUtc(networkDateTime, TimeZoneInfo.Local);
Pabinator

1
Ma poi sei fissato su un unico fuso orario. Dipende da come vuoi usare il codice immagino. :-)
Karl Gjertsen

9
Questo non è molto sicuro. Se stai esternalizzando la tua applicazione a un ambiente cloud, non sai quale fuso orario è locale di per sé.
Tom

5

Sono un principiante sia in .NET che in stackoverflow, quindi potrei sbagliarmi, ma ecco qui:

L'utilizzo di TimeZoneInfo.ConvertTimeFromUtc consentirà l'ora legale e la conversione all'ora corretta in base al fuso orario + un possibile offset dell'ora legale. Tuttavia, l'offset stesso nell'oggetto risultante mostrerà l'offset per l'ora solare e non terrà conto dell'ora legale. Quindi, se vuoi fare una ToString sull'oggetto, finirai con l'ora corretta (in ore e minuti), ma l'offset sbagliato durante l'ora legale, che potrebbe portare al momento sbagliato nel tempo più avanti nel codice.

Se invece usi GetUtcOffset per ottenere l'offset per un orario specifico e quindi esegui un ToOffset sull'oggetto DateTimeOffset, sia le ore / minuti che l'offset stesso verranno convertiti correttamente e puoi tranquillamente eseguire un ToString.

string ExpectedDateTimePattern = "yyyy'-'MM'-'dd'T'HH':'mm':'ss''zzz";
string timeZoneId = "FLE Standard Time";
string dateTimestr = "2017-10-09T09:00:00+02:00";

DateTimeOffset dto = DateTimeOffset.Parse(dateTimeStr);
TimeZoneInfo zone = TimeZoneInfo.FindSystemTimeZoneById(timeZoneId);
TimeSpan offset = zone.GetUtcOffset(dto);
dto = dto.ToOffset(offset);
string localTime = dto.ToString(ExpectedDateTimePattern);

localTime restituirà "2017-10-09T10: 00: 00 + 03: 00".


Secondo l'OP questa è la risposta corretta. La cosa principale da capire è che UtcOffset per un fuso orario non è costante, dipende invece dalla data stessa di cui stiamo parlando a causa delle regole dell'ora legale . Quindi l'unico errore che ha fatto l'OP è che ha usato la costante BaseUtcOffset invece del GetUtcOffset (myDate)
g.pickardou
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.