Konvertieren von Uhrzeiten zwischen Zeitzonen

Es wird immer wichtiger, dass Anwendungen, die mit Daten und Uhrzeiten arbeiten, Unterschiede zwischen Zeitzonen verarbeiten können. Eine Anwendung kann nicht voraussetzen, dass alle Uhrzeiten in lokaler Zeit, also in der über die DateTime-Struktur verfügbaren Zeit, ausgedrückt werden können. Eine Webseite beispielsweise, die die aktuelle Uhrzeit für die Ostküste der USA anzeigt, wird für Kunden in Ostasien an Glaubwürdigkeit verlieren. Dieser Artikel erläutert, wie Sie Uhrzeiten zwischen Zeitzonen konvertieren und wie Sie DateTimeOffset-Werte konvertieren, bei denen die Zeitzone nur in eingeschränktem Maß berücksichtigt wird.

Konvertieren in die koordinierte Weltzeit

Die koordinierte Weltzeit (UTC, Coordinated Universal Time) ist ein auf der Atomzeit basierender, höchst präziser Zeitstandard. Die Zeitzonen der Welt werden als positive oder negative Abweichungen von der UTC ausgedrückt. Daher ist die UTC eine zeitzonenfreie bzw. zeitzonenneutrale Zeit. Die Verwendung der UTC wird empfohlen, wenn die computerübergreifende Portabilität von Datum und Uhrzeit von großer Bedeutung ist. Ausführliche Informationen und andere bewährte Methoden zur Verwendung von Datums- und Uhrzeitangaben finden Sie unter Bewährte Methoden zum Programmieren von DateTime in der .NET Framework. Durch Konvertieren einzelner Zeitzonen in die UTC lassen sich Zeiten einfach miteinander vergleichen.

Hinweis

Sie können auch eine DateTimeOffset-Struktur serialisieren, um einen bestimmten Zeitpunkt eindeutig darzustellen. Da DateTimeOffset-Objekte einen Datums- und Uhrzeitwert sowie die zugehörige Abweichung von der UTC speichern, stellen sie immer einen bestimmten Zeitpunkt in Relation zur UTC dar.

Die einfachste Möglichkeit, eine Uhrzeit in die UTC zu konvertieren, ist der Aufruf der static (Shared in Visual Basic) TimeZoneInfo.ConvertTimeToUtc(DateTime)-Methode. Welche Konvertierung von der Methode genau ausgeführt wird, richtet sich nach dem Wert der Kind-Eigenschaft des dateTime-Parameters, wie in der folgenden Tabelle gezeigt:

DateTime.Kind Konvertierung
DateTimeKind.Local Konvertiert die lokale Zeit in die UTC.
DateTimeKind.Unspecified Nimmt an, dass der dateTime-Parameter die lokale Zeit angibt, und konvertiert die lokale Zeit in die UTC.
DateTimeKind.Utc Gibt den dateTime-Parameter unverändert zurück.

Der folgende Code konvertiert die aktuelle lokale Zeit in die UTC und zeigt das Ergebnis in der Konsole an.

DateTime dateNow = DateTime.Now;
Console.WriteLine($"The date and time are {TimeZoneInfo.ConvertTimeToUtc(dateNow)} UTC.");
Dim dateNow As Date = Date.Now
Console.WriteLine("The date and time are {0} UTC.", _
                  TimeZoneInfo.ConvertTimeToUtc(dateNow))

Wenn der Datums- und Uhrzeitwert weder die lokale Zeit noch die UTC-Zeit darstellt, gibt die ToUniversalTime-Methode wahrscheinlich ein falsches Ergebnis zurück. Sie können jedoch die TimeZoneInfo.ConvertTimeToUtc-Methode verwenden, um das Datum und die Uhrzeit aus einer angegebenen Zeitzone zu konvertieren. Weitere Informationen zum Abrufen eines TimeZoneInfo-Objekts, das die Zielzeitzone darstellt, finden Sie unter Suchen der in einem lokalen System definierten Zeitzonen. Der folgende Code verwendet die TimeZoneInfo.ConvertTimeToUtc-Methode, um die Eastern Standard Time in die UTC zu konvertieren:

DateTime easternTime = new DateTime(2007, 01, 02, 12, 16, 00);
string easternZoneId = "Eastern Standard Time";
try
{
    TimeZoneInfo easternZone = TimeZoneInfo.FindSystemTimeZoneById(easternZoneId);
    Console.WriteLine($"The date and time are {TimeZoneInfo.ConvertTimeToUtc(easternTime, easternZone)} UTC.");
}
catch (TimeZoneNotFoundException)
{
    Console.WriteLine($"Unable to find the {easternZoneId} zone in the registry.");
}
catch (InvalidTimeZoneException)
{
    Console.WriteLine($"Registry data on the {easternZoneId} zone has been corrupted.");
}
Dim easternTime As New Date(2007, 01, 02, 12, 16, 00)
Dim easternZoneId As String = "Eastern Standard Time"
Try
    Dim easternZone As TimeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById(easternZoneId)
    Console.WriteLine("The date and time are {0} UTC.", _
                      TimeZoneInfo.ConvertTimeToUtc(easternTime, easternZone))
Catch e As TimeZoneNotFoundException
    Console.WriteLine("Unable to find the {0} zone in the registry.", _
                      easternZoneId)
Catch e As InvalidTimeZoneException
    Console.WriteLine("Registry data on the {0} zone has been corrupted.", _
                      easternZoneId)
End Try

Die TimeZoneInfo.ConvertTimeToUtc-Methode löst eine ArgumentException aus, wenn die Kind-Eigenschaft des DateTime-Objekts und die Zeitzone nicht übereinstimmen. Ein Konflikt tritt auf, wenn die Kind-Eigenschaft DateTimeKind.Local ist, aber das TimeZoneInfo-Objekt nicht die lokale Zeitzone darstellt, oder wenn die Kind-Eigenschaft DateTimeKind.Utc ist, das TimeZoneInfo-Objekt jedoch nicht gleich TimeZoneInfo.Utc ist.

All diese Methoden akzeptieren DateTime-Werte als Parameter und geben einen DateTime-Wert zurück. Für DateTimeOffset-Werte besitzt die DateTimeOffset-Struktur eine ToUniversalTime-Instanzmethode, die das Datum und die Uhrzeit der aktuellen Instanz in die UTC konvertiert. Das folgende Beispiel ruft die ToUniversalTime-Methode auf, um eine lokale Uhrzeit sowie verschiedene weitere Uhrzeiten in die koordinierte Weltzeit zu konvertieren:

DateTimeOffset localTime, otherTime, universalTime;

// Define local time in local time zone
localTime = new DateTimeOffset(new DateTime(2007, 6, 15, 12, 0, 0));
Console.WriteLine("Local time: {0}", localTime);
Console.WriteLine();

// Convert local time to offset 0 and assign to otherTime
otherTime = localTime.ToOffset(TimeSpan.Zero);
Console.WriteLine("Other time: {0}", otherTime);
Console.WriteLine("{0} = {1}: {2}",
                  localTime, otherTime,
                  localTime.Equals(otherTime));
Console.WriteLine("{0} exactly equals {1}: {2}",
                  localTime, otherTime,
                  localTime.EqualsExact(otherTime));
Console.WriteLine();

// Convert other time to UTC
universalTime = localTime.ToUniversalTime();
Console.WriteLine("Universal time: {0}", universalTime);
Console.WriteLine("{0} = {1}: {2}",
                  otherTime, universalTime,
                  universalTime.Equals(otherTime));
Console.WriteLine("{0} exactly equals {1}: {2}",
                  otherTime, universalTime,
                  universalTime.EqualsExact(otherTime));
Console.WriteLine();
// The example produces the following output to the console:
//    Local time: 6/15/2007 12:00:00 PM -07:00
//
//    Other time: 6/15/2007 7:00:00 PM +00:00
//    6/15/2007 12:00:00 PM -07:00 = 6/15/2007 7:00:00 PM +00:00: True
//    6/15/2007 12:00:00 PM -07:00 exactly equals 6/15/2007 7:00:00 PM +00:00: False
//
//    Universal time: 6/15/2007 7:00:00 PM +00:00
//    6/15/2007 7:00:00 PM +00:00 = 6/15/2007 7:00:00 PM +00:00: True
//    6/15/2007 7:00:00 PM +00:00 exactly equals 6/15/2007 7:00:00 PM +00:00: True
Dim localTime, otherTime, universalTime As DateTimeOffset

' Define local time in local time zone
localTime = New DateTimeOffset(#6/15/2007 12:00:00PM#)
Console.WriteLine("Local time: {0}", localTime)
Console.WriteLine()

' Convert local time to offset 0 and assign to otherTime
otherTime = localTime.ToOffset(TimeSpan.Zero)
Console.WriteLine("Other time: {0}", otherTime)
Console.WriteLine("{0} = {1}: {2}", _
                  localTime, otherTime, _
                  localTime.Equals(otherTime))
Console.WriteLine("{0} exactly equals {1}: {2}", _
                  localTime, otherTime, _
                  localTime.EqualsExact(otherTime))
Console.WriteLine()

' Convert other time to UTC
universalTime = localTime.ToUniversalTime()
Console.WriteLine("Universal time: {0}", universalTime)
Console.WriteLine("{0} = {1}: {2}", _
                  otherTime, universalTime, _
                  universalTime.Equals(otherTime))
Console.WriteLine("{0} exactly equals {1}: {2}", _
                  otherTime, universalTime, _
                  universalTime.EqualsExact(otherTime))
Console.WriteLine()
' The example produces the following output to the console:
'    Local time: 6/15/2007 12:00:00 PM -07:00
'    
'    Other time: 6/15/2007 7:00:00 PM +00:00
'    6/15/2007 12:00:00 PM -07:00 = 6/15/2007 7:00:00 PM +00:00: True
'    6/15/2007 12:00:00 PM -07:00 exactly equals 6/15/2007 7:00:00 PM +00:00: False
'    
'    Universal time: 6/15/2007 7:00:00 PM +00:00
'    6/15/2007 7:00:00 PM +00:00 = 6/15/2007 7:00:00 PM +00:00: True
'    6/15/2007 7:00:00 PM +00:00 exactly equals 6/15/2007 7:00:00 PM +00:00: True   

Konvertieren der UTC in eine festgelegte Zeitzone

Informationen zum Konvertieren der UTC in eine lokale Uhrzeit finden Sie im nächsten Abschnitt, Konvertieren der UTC in eine lokale Zeit. Um die UTC in die Uhrzeit einer von Ihnen festgelegten Zeitzone zu konvertieren, rufen Sie die ConvertTimeFromUtc-Methode auf. Die Methode akzeptiert zwei Parameter:

  • Die zu konvertierende UTC. Dies muss ein DateTime-Wert sein, dessen Kind-Eigenschaft auf Unspecified oder Utc festgelegt ist.

  • Die Zeitzone, in die die UTC konvertiert werden soll.

Der folgende Code konvertiert die UTC in die Central Standard Time:

DateTime timeUtc = DateTime.UtcNow;
try
{
    TimeZoneInfo cstZone = TimeZoneInfo.FindSystemTimeZoneById("Central Standard Time");
    DateTime cstTime = TimeZoneInfo.ConvertTimeFromUtc(timeUtc, cstZone);
    Console.WriteLine("The date and time are {0} {1}.",
                      cstTime,
                      cstZone.IsDaylightSavingTime(cstTime) ?
                              cstZone.DaylightName : cstZone.StandardName);
}
catch (TimeZoneNotFoundException)
{
    Console.WriteLine("The registry does not define the Central Standard Time zone.");
}
catch (InvalidTimeZoneException)
{
    Console.WriteLine("Registry data on the Central Standard Time zone has been corrupted.");
}
Dim timeUtc As Date = Date.UtcNow
Try
    Dim cstZone As TimeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById("Central Standard Time")
    Dim cstTime As Date = TimeZoneInfo.ConvertTimeFromUtc(timeUtc, cstZone)
    Console.WriteLine("The date and time are {0} {1}.", _
                      cstTime, _
                      IIf(cstZone.IsDaylightSavingTime(cstTime), _
                          cstZone.DaylightName, cstZone.StandardName))
Catch e As TimeZoneNotFoundException
    Console.WriteLine("The registry does not define the Central Standard Time zone.")
Catch e As InvalidTimeZoneException
    Console.WriteLine("Registry data on the Central Standard Time zone has been corrupted.")
End Try

Konvertieren der UTC in eine lokale Zeit

Um die UTC in eine lokale Zeit zu konvertieren, rufen Sie die ToLocalTime-Methode des DateTime-Objekts auf, dessen Zeit Sie konvertieren möchten. Das genaue Verhalten der Methode richtet sich nach dem Wert der Kind-Eigenschaft des Objekts, wie in der folgenden Tabelle gezeigt:

DateTime.Kind Konvertierung
DateTimeKind.Local Gibt den DateTime-Wert unverändert zurück.
DateTimeKind.Unspecified Nimmt an, dass der DateTime-Wert als UTC vorliegt, und konvertiert die UTC in die lokale Zeit.
DateTimeKind.Utc Konvertiert den DateTime-Wert in die lokale Zeit.

Hinweis

Die TimeZone.ToLocalTime-Methode weist ein identisches Verhalten wie die DateTime.ToLocalTime-Methode auf. Für die Konvertierung wird ein einzelner Parameter benötigt, d. h. der Datums- und Uhrzeitwert.

Sie können die Zeit in einer beliebigen angegebenen Zeitzone auch mit der static (Shared in Visual Basic) TimeZoneInfo.ConvertTime-Methode in die lokale Zeit konvertieren. Diese Technik wird im nächsten Abschnitt behandelt.

Konvertieren zwischen zwei beliebigen Zeitzonen

Sie können zwischen zwei beliebigen Zeitzonen konvertieren, indem Sie eine der folgenden beiden static-Methoden (Shared in Visual Basic) der TimeZoneInfo-Klasse verwenden:

  • ConvertTime

    Die Parameter dieser Methode sind der zu konvertierende Datums- und Uhrzeitwert, ein TimeZoneInfo-Objekt, das die Zeitzone des Datums- und Uhrzeitwerts darstellt, und ein TimeZoneInfo-Objekt, das die Zeitzone darstellt, in die der Datums- und Uhrzeitwert konvertiert werden soll.

  • ConvertTimeBySystemTimeZoneId

    Die Parameter dieser Methode sind der zu konvertierende Datums- und Uhrzeitwert, der Bezeichner der Zeitzone des Datums- und Uhrzeitwerts und der Bezeichner der Zeitzone, in die der Datums- und Uhrzeitwert konvertiert werden soll.

Beide Methoden erfordern, dass die Kind-Eigenschaft des zu konvertierenden Datums- und Uhrzeitwerts und das TimeZoneInfo-Objekt bzw. der Zeitzonenbezeichner, der die Zeitzone repräsentiert, einander entsprechen. Andernfalls wird eine ArgumentException ausgelöst. Wenn z. B. die Kind-Eigenschaft des Datums- und Uhrzeitwerts DateTimeKind.Local lautet und das als Parameter an die Methode übergebene TimeZoneInfo-Objekt ungleich TimeZoneInfo.Local ist, wird eine Ausnahme ausgelöst. Es wird ebenfalls eine Ausnahme ausgelöst, wenn der als Parameter an die Methode übergebene Bezeichner ungleich TimeZoneInfo.Local.Id ist.

Das folgende Beispiel verwendet die ConvertTime-Methode, um aus der Hawaiian Standard Time in die lokale Zeit zu konvertieren:

DateTime hwTime = new DateTime(2007, 02, 01, 08, 00, 00);
try
{
    TimeZoneInfo hwZone = TimeZoneInfo.FindSystemTimeZoneById("Hawaiian Standard Time");
    Console.WriteLine("{0} {1} is {2} local time.",
            hwTime,
            hwZone.IsDaylightSavingTime(hwTime) ? hwZone.DaylightName : hwZone.StandardName,
            TimeZoneInfo.ConvertTime(hwTime, hwZone, TimeZoneInfo.Local));
}
catch (TimeZoneNotFoundException)
{
    Console.WriteLine("The registry does not define the Hawaiian Standard Time zone.");
}
catch (InvalidTimeZoneException)
{
    Console.WriteLine("Registry data on the Hawaiian Standard Time zone has been corrupted.");
}
Dim hwTime As Date = #2/01/2007 8:00:00 AM#
Try
    Dim hwZone As TimeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById("Hawaiian Standard Time")
    Console.WriteLine("{0} {1} is {2} local time.", _
                      hwTime, _
                      IIf(hwZone.IsDaylightSavingTime(hwTime), hwZone.DaylightName, hwZone.StandardName), _
                      TimeZoneInfo.ConvertTime(hwTime, hwZone, TimeZoneInfo.Local))
Catch e As TimeZoneNotFoundException
    Console.WriteLine("The registry does not define the Hawaiian Standard Time zone.")
Catch e As InvalidTimeZoneException
    Console.WriteLine("Registry data on the Hawaiian Standard Time zone has been corrupted.")
End Try

Konvertieren von DateTimeOffset-Werten

Datums- und Uhrzeitwerte, die durch DateTimeOffset-Objekte dargestellt werden, berücksichtigen die Zeitzone nicht vollständig, weil das Objekt zum Zeitpunkt der Instanziierung nicht mit der zugehörigen Zeitzone verknüpft ist. In vielen Fällen muss eine Anwendung jedoch einfach nur ein Datum und eine Uhrzeit basierend auf zwei verschiedenen Abweichungen von der UTC konvertieren, nicht basierend auf der Uhrzeit in bestimmten Zeitzonen. Um diese Konvertierung auszuführen, können Sie die ToOffset-Methode der aktuellen Instanz aufrufen. Der einzige Parameter dieser Methode ist die Abweichung vom neuen Datums- und Uhrzeitwert, den die Methode zurückgeben wird.

Wenn Datum und Uhrzeit einer Benutzeranforderung für eine Webseite bekannt sind und als Zeichenfolge im Format MM/dd/yyyy hh:mm:ss zzzz serialisiert wurden, konvertiert die folgende ReturnTimeOnServer-Methode diesen Datums- und Uhrzeitwert in das Datum und die Uhrzeit des Webservers:

public DateTimeOffset ReturnTimeOnServer(string clientString)
{
   string format = @"M/d/yyyy H:m:s zzz";
   TimeSpan serverOffset = TimeZoneInfo.Local.GetUtcOffset(DateTimeOffset.Now);

   try
   {
      DateTimeOffset clientTime = DateTimeOffset.ParseExact(clientString, format, CultureInfo.InvariantCulture);
      DateTimeOffset serverTime = clientTime.ToOffset(serverOffset);
      return serverTime;
   }
   catch (FormatException)
   {
      return DateTimeOffset.MinValue;
   }
}
Public Function ReturnTimeOnServer(clientString As String) As DateTimeOffset
    Dim format As String = "M/d/yyyy H:m:s zzz"
    Dim serverOffset As TimeSpan = TimeZoneInfo.Local.GetUtcOffset(DateTimeOffset.Now)

    Try
        Dim clientTime As DateTimeOffset = DateTimeOffset.ParseExact(clientString, format, CultureInfo.InvariantCulture)
        Dim serverTime As DateTimeOffset = clientTime.ToOffset(serverOffset)
        Return serverTime
    Catch e As FormatException
        Return DateTimeOffset.MinValue
    End Try
End Function

Beispiel: Wenn die Methode die Zeichenfolge „9/1/2007 5:32:07 -05:00“ übergibt, die das Datum und die Uhrzeit in einer Zeitzone darstellt, die fünf Stunden vor der UTC liegt, gibt die Methode den Wert „9/1/2007 3:32:07 AM -07:00“ zurück, wenn sich der Server in der „Pacific Standard Time“ (USA) befindet.

Die TimeZoneInfo-Klasse enthält auch eine Überladung der TimeZoneInfo.ConvertTime(DateTimeOffset, TimeZoneInfo)-Methode, die Zeitzonenkonvertierungen mit ToOffset(TimeSpan)-Werten ausführt. Die Parameter der Methode sind ein DateTimeOffset-Wert und ein Verweis auf die Zeitzone, in die die Uhrzeit konvertiert werden soll. Der Methodenaufruf gibt einen DateTimeOffset-Wert zurück. Zum Beispiel kann die ReturnTimeOnServer-Methode im vorherigen Beispiel wie folgt neu geschrieben werden, um die ConvertTime(DateTimeOffset, TimeZoneInfo)-Methode aufzurufen.

public DateTimeOffset ReturnTimeOnServer(string clientString)
{
   string format = @"M/d/yyyy H:m:s zzz";

   try
   {
      DateTimeOffset clientTime = DateTimeOffset.ParseExact(clientString, format,
                                  CultureInfo.InvariantCulture);
      DateTimeOffset serverTime = TimeZoneInfo.ConvertTime(clientTime,
                                  TimeZoneInfo.Local);
      return serverTime;
   }
   catch (FormatException)
   {
      return DateTimeOffset.MinValue;
   }
}
Public Function ReturnTimeOnServer(clientString As String) As DateTimeOffset
    Dim format As String = "M/d/yyyy H:m:s zzz"

    Try
        Dim clientTime As DateTimeOffset = DateTimeOffset.ParseExact(clientString, format, CultureInfo.InvariantCulture)
        Dim serverTime As DateTimeOffset = TimeZoneInfo.ConvertTime(clientTime, TimeZoneInfo.Local)
        Return serverTime
    Catch e As FormatException
        Return DateTimeOffset.MinValue
    End Try
End Function

Weitere Informationen