Freigeben über


Speichern und Wiederherstellen von Zeitzonen

Aktualisiert: November 2007

Die TimeZoneInfo-Klasse stützt sich auf die Registrierung, um Daten vordefinierter Zeitzonen abzurufen. Bei der Registrierung handelt es sich jedoch um eine dynamische Struktur. Zudem werden die Zeitzonendaten in der Registrierung vom Betriebssystem in erster Linie dazu verwendet, Zeitanpassungen und -umstellungen für das aktuelle Jahr vorzunehmen. Dies hat zwei wesentliche Auswirkungen auf Anwendungen, die genaue Zeitzonendaten benötigen:

  • Eine Zeitzone, die von einer Anwendung benötigt wird, ist möglicherweise nicht in der Registrierung definiert oder wurde umbenannt bzw. aus der Registrierung entfernt.

  • Eine in der Registrierung definierte Zeitzone verfügt möglicherweise nicht über alle Daten zu bestimmten Anpassungsregeln, die für die Konvertierung historischer Zeitzonen notwendig sind.

Die TimeZoneInfo-Klasse geht auf diese Einschränkungen ein, indem sie das Serialisieren (Speichern) und Deserialisieren (Wiederherstellen) von Zeitzonendaten unterstützt.

Zeitzonenserialisierung und -deserialisierung

Zum Speichern und Wiederherstellen einer Zeitzone durch Serialisierung und Deserialisierung von Zeitzonendaten müssen nur zwei Methodenaufrufe verwendet werden:

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

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

Szenarien für die Serialisierung und Deserialisierung

Durch die Möglichkeit, ein TimeZoneInfo-Objekt in einer Zeichenfolge zu speichern (zu serialisieren) und zur späteren Verwendung wiederherzustellen (zu deserialisieren), werden sowohl die Nützlichkeit als auch die Flexibilität der TimeZoneInfo-Klasse erhöht. In diesem Abschnitt werden einige Situationen erläutert, in denen die 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. Dies kann von einer Anwendung durchgeführt werden, wenn mit einer aus der Registrierung abgerufenen Zeitzone das Datum und die Uhrzeit in einem bestimmten Datumsbereich nicht ordnungsgemäß konvertiert werden können. So unterstützen zum Beispiel die Zeitzonendaten in der Registrierung von Windows XP eine einzelne Anpassungsregel, während die in der Registrierung von Windows Vista definierten Zeitzonen in der Regel Informationen zu zwei Anpassungsregeln bereitstellen. Dies bedeutet, dass historische Zeitkonvertierungen möglicherweise ungenau sind. Durch die Serialisierung und Deserialisierung von Zeitzonendaten kann diese Einschränkung umgangen werden.

Im folgenden Beispiel ist eine benutzerdefinierte TimeZoneInfo-Klasse ohne Anpassungsregeln so definiert, dass sie die Zeitzone Eastern Normalzeit von 1883 bis 1917 darstellt, bevor die Sommerzeit in den USA eingeführt wurde. Die benutzerdefinierte Zeitzone ist in einer Variablen mit globaler Gültigkeit serialisiert. An die Konvertierungsmethode der Zeitzone, ConvertUtcTime, wird eine koordinierte Weltzeit (Coordinated Universal Time, UTC) zur Konvertierung übergeben. Wenn Datum und Uhrzeit im oder vor dem Jahr 1917 liegen, wird die benutzerdefinierte Zeitzone für Eastern Normalzeit aus einer serialisierten Zeichenfolge wiederhergestellt und ersetzt die aus der Registrierung abgerufene Zeitzone.

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

Behandlung von Zeitzonenausnahmen

Da die Registrierung eine dynamische Struktur darstellt, kann ihr Inhalt versehentlich oder absichtlich geändert werden. Dies kann bedeuten, dass eine Zeitzone, die für die ordnungsgemäße Ausführung einer Anwendung notwendig ist und in der Registrierung definiert sein sollte, möglicherweise fehlt. Wenn die Serialisierung und Deserialisierung von Zeitzonen nicht unterstützt wird, kann die resultierende TimeZoneNotFoundException nur durch Beenden der Anwendung behandelt werden. Bei Verwendung der Zeitzonenserialisierung und -deserialsierung kann eine unerwartete TimeZoneNotFoundException jedoch behandelt werden, indem Sie die benötigte Zeitzone aus einer serialisierten Zeichenfolge wiederherstellen, sodass die Anwendung weiter ausgeführt wird.

Im folgenden Beispiel wird eine benutzerdefinierte Zeitzone Central Normalzeit erstellt und serialisiert. Anschließend wird versucht, die Zeitzone Central Normalzeit aus der Registrierung abzurufen. Wenn durch den Abrufvorgang entweder eine TimeZoneNotFoundException oder eine InvalidTimeZoneException ausgelöst wird, deserialisiert der Ausnahmehandler die Zeitzone.

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

Speichern einer serialisierten Zeichenfolge und Wiederherstellen bei Bedarf

In den vorherigen Beispielen wurden Zeitzonendaten in einer Zeichenfolgevariablen gespeichert und bei Bedarf wiederhergestellt. Die Zeichenfolge mit den serialisierten Zeitzonendaten selbst kann jedoch in einem beliebigen Speichermedium gespeichert werden, zum Beispiel in einer externen Datei, in einer in die Anwendung eingebetteten Ressourcendatei oder in der Registrierung. (Beachten Sie, dass Daten über benutzerdefinierte Zeitzonen getrennt von den Zeitzonenschlüsseln des Systems in der Registrierung gespeichert werden sollten.)

Indem eine serialisierte Zeitzonenzeichenfolge auf diese Weise gespeichert wird, wird die Erstellungsroutine für die Zeitzone auch von der Anwendung selbst getrennt. Eine Zeitzonenerstellungsroutine kann zum Beispiel eine Datendatei mit historischen Zeitzonendaten, die von der Anwendung verwendet werden können, ausführen und erstellen. Die Datendatei kann dann zusammen mit der Anwendung installiert werden. Sie kann geöffnet werden, und eine oder mehrere Zeitzonen in der Datei können deserialisiert werden, wenn sie von der Anwendung benötigt werden.

Ein Beispiel für die Verwendung einer eingebetteten Ressource zum Speichern serialisierter Zeitzonendaten finden Sie unter Gewusst wie: Speichern von Zeitzonen in einer eingebetteten Ressource und Gewusst wie: Wiederherstellen von Zeitzonen aus einer eingebetteten Ressource.

Siehe auch

Weitere Ressourcen

Uhrzeiten und Zeitzonen