Wie verwende ich TimeZoneInfo, um die Ortszeit während der Sommerzeit abzurufen?

82

Ich versuche DateTimeOffset, einen bestimmten Zeitpunkt in einer beliebigen Zeitzone zu vermitteln. Ich kann nicht herausfinden, wie ich TimeZoneInfomit der Sommerzeit umgehen soll.

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

Dies druckt aus:

02.06.2010 16:37:19 Uhr
02.06.2010 15:37:19 -06: 00 Uhr

Ich bin in der zentralen Zeitzone und wir sind derzeit in der Sommerzeit. Ich versuche, die zweite Zeile zum Lesen zu bringen:

02.06.2010 16:37:19 -05: 00 Uhr

BaseUtcOffset anscheinend ändert sich nicht basierend auf der Sommerzeit.

Wie kann ich mit dem richtigen Versatzwert den richtigen Zeitpunkt ermitteln?

Jaminto
quelle
13
+1 - es macht mich wahnsinnig, dass TimeZoneInfo.ConvertTimeBySystemTimeZoneId nicht nur dafür funktioniert :)
James Manning
@ JamesManning - Vorausgesetzt, es dt.Kindist richtig eingestellt.
Matt Johnson-Pint

Antworten:

58

Sie müssen das UtcOffset aus TimeZoneInfo abrufen und dann an die ToOffset () -Methode übergeben:

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)));
Paul Kearney - pk
quelle
Ich verstehe ... Sie müssen den UTC-Offset für dieses bestimmte Datum in der Zeitzone erhalten. Vielen Dank.
Jaminto
5
Dies ist nicht der beste Weg im Vergleich zu Karl Gjertsens Antwort, bei der eine einzige .Net-Funktion verwendet wird, um den Job zu erledigen, anstatt den Offset durch Erstellen eines neuen Wegwerfgeräts zu extrahieren DateTimeOffset.
ErikE
57

Sie können auch TimeZoneInfo.ConvertTimeFromUtc verwenden, um die Sommerzeit zu berücksichtigen:

DateTime utc = DateTime.UtcNow;
TimeZoneInfo zone = TimeZoneInfo.FindSystemTimeZoneById("Central Standard Time");
DateTime localDateTime = TimeZoneInfo.ConvertTimeFromUtc(utc, zone);
Karl Gjertsen
quelle
Was ist, wenn die Zeitzone meines Landes im Sommer EEST und im Winter EET ist? Wie würde das mit der Sommerzeit funktionieren?
Rami Zebian
1
Windows kennt die Zeitzoneninformationen sowie die Sommerzeitdaten. Es sollte klappen oder Sie, wenn Sie eine der vordefinierten Zeitzonen wählen.
Karl Gjertsen
10

Oder besser, wenn Sie die Zeitzonen-ID nicht fest codieren möchten :

TimeZoneInfo tzi = TimeZoneInfo.FindSystemTimeZoneById(TimeZoneInfo.Local.Id);
DateTime localDateTime = TimeZoneInfo.ConvertTimeFromUtc(DateTime.UtcNow, tzi);
Pabinator
quelle
2
Könnten Sie nicht einfach TimeZoneInfo.Localdirekt verwenden? Warum brauchen Sie den Anruf bei FindSystemTimeZoneById?
CoderDennis
4
Sie haben Recht, wir brauchen es nicht. Wir können es einfach so machenDateTime localDateTime = TimeZoneInfo.ConvertTimeFromUtc(networkDateTime, TimeZoneInfo.Local);
Pabinator
1
Aber dann sind Sie auf eine einzelne Zeitzone festgelegt. Kommt darauf an, wie du den Code verwenden willst, denke ich. :-)
Karl Gjertsen
9
Das ist nicht sehr sicher. Wenn Sie Ihre Anwendung in eine Cloud-Umgebung auslagern, wissen Sie nicht, welche Zeitzone per se lokal ist.
Tom
4

Ich bin ein Anfänger sowohl bei .NET als auch bei Stackoverflow, daher könnte ich mich irren, aber hier ist:

Die Verwendung von TimeZoneInfo.ConvertTimeFromUtc ermöglicht die Sommerzeit und konvertiert in die richtige Zeit entsprechend der Zeitzone + einem möglichen Sommerzeitversatz. Der Versatz selbst im resultierenden Objekt zeigt jedoch den Versatz für die Standardzeit an und berücksichtigt nicht die Sommerzeit. Wenn Sie also einen ToString für das Objekt ausführen möchten, erhalten Sie die richtige Zeit (in Stunden und Minuten), aber den falschen Versatz während der Sommerzeit, was später im Code zu einem falschen Zeitpunkt führen kann.

Wenn Sie stattdessen GetUtcOffset verwenden, um den Offset für eine bestimmte Zeit abzurufen, und dann ein ToOffset für das DateTimeOffset-Objekt ausführen, werden sowohl die Stunden / Minuten als auch der Offset selbst korrekt konvertiert, und Sie können sicher einen ToString ausführen.

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 gibt "2017-10-09T10: 00: 00 + 03: 00" zurück.

Niels Pein
quelle
Laut OP ist dies die richtige Antwort. Das Wichtigste ist, dass UtcOffset für eine Zeitzone nicht konstant ist, sondern aufgrund der Sommerzeitregeln vom Datum selbst abhängt, über das wir sprechen . Der einzige Fehler, den das OP gemacht hat, ist, dass er die Konstante BaseUtcOffset anstelle des GetUtcOffset (myDate) verwendet hat
g.pickardou