Freigeben über


Speichern und Wiederherstellen von Zeitzonen

Die TimeZoneInfo-Klasse ruft vordefinierte Zeitzonendaten aus der Registrierung ab. Die Registrierung ist jedoch eine dynamische Struktur. Darüber hinaus werden die in der Registrierung enthaltenen Zeitzoneninformationen vom Betriebssystem hauptsächlich verwendet, um Zeitanpassungen und Konvertierungen für das aktuelle Jahr zu verarbeiten. Dies hat zwei wesentliche Auswirkungen auf Anwendungen, die präzise Zeitzonendaten benötigen:

  • Möglicherweise ist eine Zeitzone, die für eine Anwendung erforderlich ist, nicht in der Registrierung definiert oder wurde umbenannt bzw. aus der Registrierung entfernt.

  • Für eine Zeitzone, die in der Registrierung definiert ist, fehlen möglicherweise Informationen zu speziellen Anpassungsregeln, die für zurückliegende Zeitzonenkonvertierungen erforderlich sind.

Die TimeZoneInfo-Klasse beseitigt diese Einschränkungen durch die Unterstützung der Serialisierung (Speicherung) und Deserialisierung (Wiederherstellung) von Zeitzonendaten.

Serialisierung und Deserialisierung von Zeitzonen

Das Speichern und Wiederherstellen einer Zeitzone durch Serialisieren und Deserialisieren von Zeitzonendaten umfasst lediglich zwei Methodenaufrufe:

  • Sie können ein TimeZoneInfo-Objekt serialisieren, indem Sie die ToSerializedString-Methode dieses Objekts aufrufen. Die Methode akzeptiert keine Parameter und gibt eine Zeichenfolge zurück, die Zeitzoneninformationen enthält.

  • Sie können ein TimeZoneInfo-Objekt aus einer serialisierten Zeichenfolge deserialisieren, indem Sie diese Zeichenfolge an die staticTimeZoneInfo.FromSerializedString-Methode (Shared in Visual Basic) übergeben.

Serialisierungs- und Deserialisierungsszenarien

Die Möglichkeit, ein TimeZoneInfo-Objekt in einer Zeichenfolge zu speichern (zu serialisieren) und es für die spätere Verwendung wiederherzustellen (zu deserialisieren), erweitert die Einsatzmöglichkeiten und die Flexibilität der TimeZoneInfo-Klasse. In diesem Abschnitt werden einige der Situationen untersucht, in denen Serialisierung und Deserialisierung am nützlichsten sind.

Serialisieren und Deserialisieren von Zeitzonendaten in einer Anwendung

Eine serialisierte Zeitzone kann bei Bedarf aus einer Zeichenfolge wiederhergestellt werden. Eine Anwendung kann dies ausführen, wenn die aus der Registrierung abgerufene Zeitzone ein Datum und eine Uhrzeit innerhalb eines bestimmten Datumsbereichs nicht ordnungsgemäß konvertieren kann. Beispielsweise unterstützen Zeitzonendaten in der Windows XP-Registrierung eine einzelne Anpassungsregel, während in der Windows Vista-Registrierung definierte Zeitzonen in der Regel Informationen zu zwei Anpassungsregeln bereitstellen. Dies bedeutet, dass frühere Zeitkonvertierungen möglicherweise ungenau sind. Die Serialisierung und Deserialisierung von Zeitzonendaten kann diese Einschränkung aufheben.

Im folgenden Beispiel wird eine benutzerdefinierte TimeZoneInfo-Klasse ohne Anpassungsregeln definiert, um die Zeitzone „Eastern Standard Time“ von 1883 bis 1917 vor der Einführung der Sommerzeit in der USA darzustellen. Die benutzerdefinierte Zeitzone wird in einer globalen Variable serialisiert. Der ConvertUtcTime-Methode zur Zeitzonenkonvertierung werden die zu konvertierenden Zeitdaten in koordinierter Weltzeit (UTC) übergeben. Wenn Datum und die Uhrzeit im Jahr 1917 oder früher liegen, wird die benutzerdefinierte Zeitzone „Eastern Standard Time“ aus einer serialisierten Zeichenfolge wiederhergestellt, um die Zeitzone zu ersetzen, die aus der Registrierung abgerufen wurde.

using System;

public class TimeZoneSerialization
{
   static string serializedEst;

   public static void Main()
   {
      // Retrieve Eastern Standard Time zone from registry
      try
      {
         TimeZoneSerialization tzs = new TimeZoneSerialization();
         TimeZoneInfo est = TimeZoneInfo.FindSystemTimeZoneById("Eastern Standard Time");
         // Create custom Eastern Time Zone for historical (pre-1918) conversions
         CreateTimeZone();
         // Call conversion function with one current and one pre-1918 date and time
         Console.WriteLine(ConvertUtcTime(DateTime.UtcNow, est));
         Console.WriteLine(ConvertUtcTime(new DateTime(1900, 11, 15, 9, 32, 00, DateTimeKind.Utc), est));
      }
      catch (TimeZoneNotFoundException)
      {
         Console.WriteLine("The Eastern Standard Time zone is not in the registry.");
      }
      catch (InvalidTimeZoneException)
      {
         Console.WriteLine("Data on the Eastern Standard Time Zone in the registry is corrupted.");
      }
   }

   private static void CreateTimeZone()
   {
      // Create a simple Eastern Standard time zone
      // without adjustment rules for 1883-1918
      TimeZoneInfo earlyEstZone = TimeZoneInfo.CreateCustomTimeZone("Eastern Standard Time",
                                      new TimeSpan(-5, 0, 0),
                                      " (GMT-05:00) Eastern Time (United States)",
                                      "Eastern Standard Time");
      serializedEst = earlyEstZone.ToSerializedString();
   }

   private static DateTime ConvertUtcTime(DateTime utcDate, TimeZoneInfo tz)
   {
      // Use time zone object from registry
      if (utcDate.Year > 1917)
      {
         return TimeZoneInfo.ConvertTimeFromUtc(utcDate, tz);
      }
      // Handle dates before introduction of DST
      else
      {
         // Restore serialized time zone object
         tz = TimeZoneInfo.FromSerializedString(serializedEst);
         return TimeZoneInfo.ConvertTimeFromUtc(utcDate, tz);
      }
   }
}
Module TimeZoneSerialization
    Dim serializedEst As String

    Public Sub Main()
        ' Retrieve Eastern Standard Time zone from registry
        Try
            Dim est As TimeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById("Eastern Standard Time")
            ' Create custom Eastern Time Zone for historical (pre-1918) conversions
            CreateTimeZone()
            ' Call conversion function with one current and one pre-1918 date and time
            Console.WriteLine(ConvertUtcTime(Date.UtcNow, est))
            Console.WriteLine(ConvertUtcTime(New Date(1900, 11, 15, 9, 32, 00, DateTimeKind.Utc), est))
        Catch e As TimeZoneNotFoundException
            Console.WriteLine("The Eastern Standard Time zone is not in the registry.")
        Catch e As InvalidTimeZoneException
            Console.WriteLine("Data on the Eastern Standard Time Zone in the registry is corrupted.")
        End Try
    End Sub

    Private Sub CreateTimeZone()
        ' Create a simple Eastern Standard time zone 
        ' without adjustment rules for 1883-1918
        Dim earlyEstZone As TimeZoneInfo = TimeZoneInfo.CreateCustomTimeZone("Eastern Standard Time", _
                                        New TimeSpan(-5, 0, 0), _
                                        " (GMT-05:00) Eastern Time (United States)", _
                                        "Eastern Standard Time")
        serializedEst = earlyEstZone.ToSerializedString()
    End Sub

    Private Function ConvertUtcTime(utcDate As Date, tz As TimeZoneInfo) As Date
        ' Use time zone object from registry 
        If Year(utcDate) > 1917 Then
            Return TimeZoneInfo.ConvertTimeFromUtc(utcDate, tz)
            ' Handle dates before introduction of DST
        Else
            ' Restore serialized time zone object
            tz = TimeZoneInfo.FromSerializedString(serializedEst)
            Return TimeZoneInfo.ConvertTimeFromUtc(utcDate, tz)
        End If
    End Function
End Module

Behandeln von Zeitzonenausnahmen

Da es sich bei der Registrierung um eine dynamische Struktur handelt, kann ihr Inhalt versehentlich oder absichtlich geändert werden. Dies kann dazu führen, dass eine Zeitzone, die in der Registrierung definiert sein sollte und die für die erfolgreiche Ausführung einer Anwendung erforderlich ist, möglicherweise nicht vorhanden ist. Ohne Unterstützung für die Zeitzonenserialisierung und -deserialisierung haben Sie kaum eine andere Wahl, als die resultierende TimeZoneNotFoundException zu behandeln, indem Sie die Anwendung beenden. Mithilfe der Zeitzonenserialisierung und -deserialisierung können Sie jedoch unerwartete TimeZoneNotFoundException verarbeiten, indem Sie die erforderliche Zeitzone aus einer serialisierten Zeichenfolge wiederherstellen, sodass die Anwendungsausführung fortgesetzt werden kann.

Im folgenden Beispiel wird die benutzerdefinierte Zeitzone „Central Standard Time“ erstellt und serialisiert. Anschließend wird versucht, die Zeitzone „Central Standard Time“ aus der Registrierung abzurufen. Wenn der Abrufvorgang eine TimeZoneNotFoundException oder eine InvalidTimeZoneException auslöst, deserialisiert der Ausnahmehandler die Zeitzone.

using System;
using System.Collections.Generic;

public class TimeZoneApplication
{
   // Define collection of custom time zones
   private Dictionary<string, string> customTimeZones = new Dictionary<string, string>();
   private TimeZoneInfo cst;

   public TimeZoneApplication()
   {
      // Create custom Central Standard Time
      //
      // Declare necessary TimeZoneInfo.AdjustmentRule objects for time zone
      TimeZoneInfo customTimeZone;
      TimeSpan delta = new TimeSpan(1, 0, 0);
      TimeZoneInfo.AdjustmentRule adjustment;
      List<TimeZoneInfo.AdjustmentRule> adjustmentList = new List<TimeZoneInfo.AdjustmentRule>();
      // Declare transition time variables to hold transition time information
      TimeZoneInfo.TransitionTime transitionRuleStart, transitionRuleEnd;

      // Define end rule (for 1976-2006)
      transitionRuleEnd = TimeZoneInfo.TransitionTime.CreateFloatingDateRule(new DateTime(1, 1, 1, 2, 0, 0), 10, 5, DayOfWeek.Sunday);
      // Define rule (1976-1986)
      transitionRuleStart = TimeZoneInfo.TransitionTime.CreateFloatingDateRule(new DateTime(1, 1, 1, 2, 0, 0), 04, 05, DayOfWeek.Sunday);
      adjustment = TimeZoneInfo.AdjustmentRule.CreateAdjustmentRule(new DateTime(1976, 1, 1), new DateTime(1986, 12, 31), delta, transitionRuleStart, transitionRuleEnd);
      adjustmentList.Add(adjustment);
      // Define rule (1987-2006)
      transitionRuleStart = TimeZoneInfo.TransitionTime.CreateFloatingDateRule(new DateTime(1, 1, 1, 2, 0, 0), 04, 01, DayOfWeek.Sunday);
      adjustment = TimeZoneInfo.AdjustmentRule.CreateAdjustmentRule(new DateTime(1987, 1, 1), new DateTime(2006, 12, 31), delta, transitionRuleStart, transitionRuleEnd);
      adjustmentList.Add(adjustment);
      // Define rule (2007- )
      transitionRuleStart = TimeZoneInfo.TransitionTime.CreateFloatingDateRule(new DateTime(1, 1, 1, 2, 0, 0), 03, 02, DayOfWeek.Sunday);
      transitionRuleEnd = TimeZoneInfo.TransitionTime.CreateFloatingDateRule(new DateTime(1, 1, 1, 2, 0, 0), 11, 01, DayOfWeek.Sunday);
      adjustment = TimeZoneInfo.AdjustmentRule.CreateAdjustmentRule(new DateTime(2007, 01, 01), DateTime.MaxValue.Date, delta, transitionRuleStart, transitionRuleEnd);
      adjustmentList.Add(adjustment);

      // Create custom U.S. Central Standard Time zone
      customTimeZone = TimeZoneInfo.CreateCustomTimeZone("Central Standard Time",
                      new TimeSpan(-6, 0, 0),
                      "(GMT-06:00) Central Time (US Only)", "Central Standard Time",
                      "Central Daylight Time", adjustmentList.ToArray());
      // Add time zone to collection
      customTimeZones.Add(customTimeZone.Id, customTimeZone.ToSerializedString());

      // Create any other required time zones
   }

   public static void Main()
   {
      TimeZoneApplication tza = new TimeZoneApplication();
      tza.AppEntryPoint();
   }

   private void AppEntryPoint()
   {
      try
      {
         cst = TimeZoneInfo.FindSystemTimeZoneById("Central Standard Time");
      }
      catch (TimeZoneNotFoundException)
      {
         if (customTimeZones.ContainsKey("Central Standard Time"))
            HandleTimeZoneException("Central Standard Time");
      }
      catch (InvalidTimeZoneException)
      {
         if (customTimeZones.ContainsKey("Central Standard Time"))
            HandleTimeZoneException("Central Standard Time");
      }
      if (cst == null)
      {
         Console.WriteLine("Unable to load Central Standard Time zone.");
         return;
      }
      DateTime currentTime = DateTime.Now;
      Console.WriteLine("The current {0} time is {1}.",
                        TimeZoneInfo.Local.IsDaylightSavingTime(currentTime) ?
                            TimeZoneInfo.Local.StandardName :
                            TimeZoneInfo.Local.DaylightName,
                        currentTime.ToString("f"));
      Console.WriteLine("The current {0} time is {1}.",
                        cst.IsDaylightSavingTime(currentTime) ?
                            cst.StandardName :
                            cst.DaylightName,
                        TimeZoneInfo.ConvertTime(currentTime, TimeZoneInfo.Local, cst).ToString("f"));
   }

   private void HandleTimeZoneException(string timeZoneName)
   {
      string tzString = customTimeZones[timeZoneName];
      cst = TimeZoneInfo.FromSerializedString(tzString);
   }
}
Imports System.Collections.Generic

Public Class TimeZoneApplication
    ' Define collection of custom time zones
    Private customTimeZones As New Dictionary(Of String, String)
    Private cst As TimeZoneInfo

    Public Sub New()
        ' Define custom Central Standard Time
        '
        ' Declare necessary TimeZoneInfo.AdjustmentRule objects for time zone
        Dim customTimeZone As TimeZoneInfo
        Dim delta As New TimeSpan(1, 0, 0)
        Dim adjustment As TimeZoneInfo.AdjustmentRule
        Dim adjustmentList As New List(Of TimeZoneInfo.AdjustmentRule)
        ' Declare transition time variables to hold transition time information
        Dim transitionRuleStart, transitionRuleEnd As TimeZoneInfo.TransitionTime

        ' Define end rule (for 1976-2006)
        transitionRuleEnd = TimeZoneInfo.TransitionTime.CreateFloatingDateRule(#02:00:00AM#, 10, 5, DayOfWeek.Sunday)
        ' Define rule (1976-1986)
        transitionRuleStart = TimeZoneInfo.TransitionTime.CreateFloatingDateRule(#2:00:00AM#, 04, 05, DayOfWeek.Sunday)
        adjustment = TimeZoneInfo.AdjustmentRule.CreateAdjustmentRule(#01/01/1976#, #12/31/1986#, delta, transitionRuleStart, transitionRuleEnd)
        adjustmentList.Add(adjustment)
        ' Define rule (1987-2006)  
        transitionRuleStart = TimeZoneInfo.TransitionTime.CreateFloatingDateRule(#2:00:00AM#, 04, 01, DayOfWeek.Sunday)
        adjustment = TimeZoneInfo.AdjustmentRule.CreateAdjustmentRule(#01/01/1987#, #12/31/2006#, delta, transitionRuleStart, transitionRuleEnd)
        adjustmentList.Add(adjustment)
        ' Define rule (2007- )  
        transitionRuleStart = TimeZoneInfo.TransitionTime.CreateFloatingDateRule(#2:00:00AM#, 03, 02, DayOfWeek.Sunday)
        transitionRuleEnd = TimeZoneInfo.TransitionTime.CreateFloatingDateRule(#2:00:00AM#, 11, 01, DayOfWeek.Sunday)
        adjustment = TimeZoneInfo.AdjustmentRule.CreateAdjustmentRule(#01/01/2007#, Date.MaxValue.Date, delta, transitionRuleStart, transitionRuleEnd)
        adjustmentList.Add(adjustment)
        ' Create custom time zone
        customTimeZone = TimeZoneInfo.CreateCustomTimeZone("Central Standard Time", _
                        New TimeSpan(-6, 0, 0), _
                        "(GMT-06:00) Central Time (US Only)", "Central Standard Time", _
                        "Central Daylight Time", adjustmentList.ToArray())
        ' Add time zone to collection
        customTimeZones.Add(customTimeZone.Id, customTimeZone.ToSerializedString())

        ' Create any other required time zones     
    End Sub

    Public Shared Sub Main()
        Dim tza As New TimeZoneApplication()
        tza.AppEntryPoint()
    End Sub

    Private Sub AppEntryPoint()
        Try
            cst = TimeZoneInfo.FindSystemTimeZoneById("Central Standard Time")
        Catch e As TimeZoneNotFoundException
            If customTimeZones.ContainsKey("Central Standard Time")
                HandleTimeZoneException("Central Standard Time")
            End If
        Catch e As InvalidTimeZoneException
            If customTimeZones.ContainsKey("Central Standard Time")
                HandleTimeZoneException("Central Standard Time")
            End If
        End Try
        If cst Is Nothing Then
            Console.WriteLine("Unable to load Central Standard Time zone.")
            Return
        End If
        Dim currentTime As Date = Date.Now
        Console.WriteLine("The current {0} time is {1}.", _
                          IIf(TimeZoneInfo.Local.IsDaylightSavingTime(currentTime), _
                              TimeZoneInfo.Local.StandardName, _
                              TimeZoneInfo.Local.DaylightName), _
                          currentTime.ToString("f"))
        Console.WriteLine("The current {0} time is {1}.", _
                          IIf(cst.IsDaylightSavingTime(currentTime), _
                              cst.StandardName, _
                              cst.DaylightName), _
                          TimeZoneInfo.ConvertTime(currentTime, TimeZoneInfo.Local, cst).ToString("f"))
    End Sub

    Private Sub HandleTimeZoneException(timeZoneName As String)
        Dim tzString As String = customTimeZones.Item(timeZoneName)
        cst = TimeZoneInfo.FromSerializedString(tzString)
    End Sub
End Class

Speichern einer serialisierten Zeichenfolge und Wiederherstellung bei Bedarf

In den vorherigen Beispielen wurden Zeitzoneninformationen in einer Zeichenfolgenvariable gespeichert und bei Bedarf wiederhergestellt. Die Zeichenfolge mit den serialisierten Zeitzoneninformationen kann jedoch selbst auf einem Speichermedium gespeichert werden, z. B. in einer externen Datei, einer in die Anwendung eingebetteten Ressourcendatei oder der Registrierung. (Beachten Sie, dass Informationen zu benutzerdefinierten Zeitzonen nicht in den Zeitzonenschlüsseln des Systems in der Registrierung gespeichert werden sollten.)

Durch dieses Verfahren zur Speicherung einer serialisierten Zeitzonenzeichenfolge wird auch die Routine zur Zeitzonenerstellung von der Anwendung selbst getrennt. So könnte beispielsweise eine Routine zur Zeitzonenerstellung eine Datendatei ausführen und erstellen, die historische Zeitzoneninformationen enthält, die von Anwendungen verwenden werden können. Die Datendatei kann dann mit der Anwendung installiert werden, von der sie geöffnet werden kann, um Zeitzonen zu deserialisieren, wenn die Anwendung sie benötigt.

Ein Beispiel, das eine eingebettete Ressource zum Speichern serialisierter Zeitzonendaten verwendet, finden Sie unter Speichern von Zeitzonen in einer eingebetteten Ressource und Wiederherstellen von Zeitzonen aus einer eingebetteten Ressource.

Weitere Informationen