Delen via


Tijdzones opslaan en herstellen

De TimeZoneInfo klasse is afhankelijk van het register om vooraf gedefinieerde tijdzonegegevens op te halen. Het register is echter een dynamische structuur. Daarnaast wordt de tijdzone-informatie die het register bevat, voornamelijk door het besturingssysteem gebruikt om tijdaanpassingen en conversies voor het huidige jaar af te handelen. Dit heeft twee belangrijke gevolgen voor toepassingen die afhankelijk zijn van nauwkeurige tijdzonegegevens:

  • Een tijdzone die door een toepassing is vereist, kan niet worden gedefinieerd in het register of de naam ervan is gewijzigd of verwijderd uit het register.

  • Een tijdzone die in het register is gedefinieerd, kan geen informatie bevatten over de specifieke aanpassingsregels die nodig zijn voor historische tijdzoneconversies.

De TimeZoneInfo klasse behandelt deze beperkingen via de ondersteuning voor serialisatie (opslaan) en deserialisatie (herstellen) van tijdzonegegevens.

Serialisatie en deserialisatie van tijdzones

Het opslaan en herstellen van een tijdzone door het serialiseren en deserialiseren van tijdzonegegevens omvat slechts twee methodeaanroepen:

  • U kunt een TimeZoneInfo object serialiseren door de methode van ToSerializedString dat object aan te roepen. De methode gebruikt geen parameters en retourneert een tekenreeks die tijdzone-informatie bevat.

  • U kunt een TimeZoneInfo object deserialiseren vanuit een geserialiseerde tekenreeks door die tekenreeks door te geven aan de static methode (Sharedin Visual Basic). TimeZoneInfo.FromSerializedString

Serialisatie- en deserialisatiescenario's

De mogelijkheid om een TimeZoneInfo object op te slaan (of te serialiseren) naar een tekenreeks en om het te herstellen (of deserialiseren) voor later gebruik verhoogt zowel het hulpprogramma als de flexibiliteit van de TimeZoneInfo klasse. In deze sectie worden enkele van de situaties onderzocht waarin serialisatie en deserialisatie het nuttigst zijn.

Tijdzonegegevens serialiseren en deserialiseren in een toepassing

Een geserialiseerde tijdzone kan worden hersteld vanuit een tekenreeks wanneer deze nodig is. Een toepassing kan dit doen als de tijdzone die is opgehaald uit het register, een datum en tijd binnen een bepaald datumbereik niet correct kan converteren. Tijdzonegegevens in het Windows XP-register ondersteunen bijvoorbeeld één aanpassingsregel, terwijl tijdzones die in het Windows Vista-register zijn gedefinieerd, doorgaans informatie bevatten over twee aanpassingsregels. Dit betekent dat historische tijdconversies mogelijk onnauwkeurig zijn. Serialisatie en deserialisatie van tijdzonegegevens kunnen deze beperking afhandelen.

In het volgende voorbeeld wordt een aangepaste TimeZoneInfo klasse die geen aanpassingsregels heeft gedefinieerd om de zone U.S. Eastern Standard Time van 1883 tot 1917 weer te geven vóór de introductie van zomertijd in de Verenigde Staten. De aangepaste tijdzone wordt geserialiseerd in een variabele met globaal bereik. De tijdzoneconversiemethode, wordt ConvertUtcTimeUTC-tijden (Coordinated Universal Time) doorgegeven om te converteren. Als de datum en tijd plaatsvinden in 1917 of eerder, wordt de aangepaste Eastern Standard Time-zone hersteld van een geserialiseerde tekenreeks en wordt de tijdzone vervangen die uit het register is opgehaald.

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

Tijdzone-uitzonderingen verwerken

Omdat het register een dynamische structuur is, kan de inhoud per ongeluk of opzettelijk worden gewijzigd. Dit betekent dat een tijdzone die moet worden gedefinieerd in het register en dat vereist is voor een toepassing die kan worden uitgevoerd, afwezig is. Zonder ondersteuning voor serialisatie en deserialisatie van tijdzones hebt u weinig keuze, maar kunt u het resultaat TimeZoneNotFoundException afhandelen door de toepassing te beëindigen. Door tijdzones te serialiseren en deserialisatie te gebruiken, kunt u echter een onverwachte TimeZoneNotFoundException bewerking uitvoeren door de vereiste tijdzone te herstellen vanuit een geserialiseerde tekenreeks en blijft de toepassing actief.

In het volgende voorbeeld wordt een aangepaste Central Standard Time-zone gemaakt en geserialiseerd. Vervolgens wordt geprobeerd de Central Standard Time-zone op te halen uit het register. Als de ophaalbewerking een TimeZoneNotFoundException of een InvalidTimeZoneExceptiongenereert, wordt de tijdzone gedeserialiseerd door de uitzonderingshandler.

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

Een geserialiseerde tekenreeks opslaan en deze herstellen wanneer dat nodig is

In de vorige voorbeelden zijn tijdzonegegevens opgeslagen in een tekenreeksvariabele en hersteld wanneer dat nodig is. De tekenreeks met geserialiseerde tijdzonegegevens kan echter zelf worden opgeslagen in een opslagmedium, zoals een extern bestand, een bronbestand dat is ingesloten in de toepassing of het register. (Houd er rekening mee dat informatie over aangepaste tijdzones moet worden opgeslagen, behalve de tijdzonesleutels van het systeem in het register.)

Als u een geserialiseerde tijdzonetekenreeks op deze manier opslaat, wordt ook de routine voor het maken van tijdzones gescheiden van de toepassing zelf. Een routine voor het maken van een tijdzone kan bijvoorbeeld een gegevensbestand uitvoeren en maken dat historische tijdzonegegevens bevat die een toepassing kan gebruiken. Het gegevensbestand kan vervolgens worden geïnstalleerd met de toepassing en kan worden geopend en een of meer van de tijdzones kunnen worden gedeserialiseerd wanneer de toepassing deze nodig heeft.

Voor een voorbeeld waarin een ingesloten resource wordt gebruikt om geserialiseerde tijdzonegegevens op te slaan, raadpleegt u Het volgende: Tijdzones opslaan in een ingesloten resource en Procedures: Tijdzones herstellen vanuit een ingesloten resource.

Zie ook