Partager via


Enregistrement et restauration de fuseaux horaires

Mise à jour : novembre 2007

La classe TimeZoneInfo dépend du Registre pour récupérer des données de fuseau horaire prédéfinies. Toutefois, le Registre est une structure dynamique. En outre, les informations de fuseau horaire présentes dans le Registre sont surtout utilisées par le système d'exploitation pour gérer les ajustements et les conversions horaires de l'année en cours. Cela a deux conséquences majeures pour les applications qui requièrent des données de fuseau horaire exactes :

  • Il se peut qu'un fuseau horaire requis par une application ne soit pas défini dans le Registre ou qu'il ait été renommé ou supprimé du Registre.

  • Il se peut qu'un fuseau horaire défini dans le Registre manque d'informations sur les règles d'ajustement spécifiques nécessaires aux conversions de fuseau horaire historiques.

La classe TimeZoneInfo surmonte ces limitations en prenant en charge la sérialisation (enregistrement) et la désérialisation (restauration) des données de fuseau horaire.

Sérialisation et désérialisation de fuseau horaire

L'enregistrement et la restauration d'un fuseau horaire en sérialisant et désérialisant des données de fuseau horaire supposent deux appels de méthode uniquement :

  • Vous pouvez sérialiser un objet TimeZoneInfo en appelant la méthode ToSerializedString de cet objet. La méthode n'accepte aucun paramètre et retourne une chaîne qui contient des informations de fuseau horaire.

  • Vous pouvez désérialiser un objet TimeZoneInfo à partir d'une chaîne sérialisée en passant cette chaîne à la méthode static (Shared dans Visual Basic) TimeZoneInfo.FromSerializedString.

Scénarios de sérialisation et de désérialisation

La capacité d'enregistrer (ou de sérialiser) un objet TimeZoneInfo sur une chaîne et de le restaurer (ou le désérialiser) en vue d'une utilisation ultérieure accroît l'utilité et la souplesse de la classe TimeZoneInfo. Cette section examine quelques situations dans lesquelles la sérialisation et la désérialisation sont très utiles.

Sérialisation et désérialisation de données de fuseau horaire dans une application

Un fuseau horaire sérialisé peut être restauré à partir d'une chaîne, le cas échéant. Une application peut effectuer cette restauration si le fuseau horaire récupéré du Registre ne peut pas convertir correctement une date et une heure dans une plage de dates donnée. Par exemple, les données de fuseau horaire du Registre Windows XP prennent en charge une seule règle d'ajustement, tandis que les fuseaux horaires définis dans le Registre Windows Vista fournissent généralement des informations concernant deux règles d'ajustement. Cela signifie que les conversions d'heures historiques peuvent être inexactes. La sérialisation et la désérialisation des données de fuseau horaire peuvent gérer cette limitation.

Dans l'exemple suivant, une classe TimeZoneInfo personnalisée sans règles d'ajustement est définie pour représenter le fuseau horaire de la côte est des États-Unis de 1883 à 1917, avant l'introduction de l'heure d'été aux États-Unis. Le fuseau horaire personnalisé est sérialisé dans une variable de portée globale. La méthode de conversion de fuseau horaire, ConvertUtcTime, est passée pour convertir le temps universel coordonné (UTC, Coordinated Universal Time). Si la date et l'heure se produisent en 1917 ou avant, fuseau horaire personnalisé de la côte est des États-Unis est restauré à partir d'une chaîne sérialisée et remplace le fuseau horaire récupéré du Registre.

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

Gestion des exceptions de fuseau horaire

Comme le Registre est une structure dynamique, son contenu peut être modifié délibérément ou accidentellement. Il se peut donc qu'un fuseau horaire nécessaire à l'exécution d'une application et qui devrait être défini dans le Registre soit absent. Si la sérialisation et la désérialisation de fuseau horaire ne sont pas prises en charge, il ne vous reste plus qu'à gérer l'exception TimeZoneNotFoundException résultante en mettant fin à l'application. Toutefois, si vous faites appel à la sérialisation et à la désérialisation de fuseau horaire, vous pouvez gérer une exception TimeZoneNotFoundException inattendue en restaurant le fuseau horaire requis à partir d'une chaîne sérialisée. L'application pourra alors poursuivre son exécution.

L'exemple suivant crée et sérialise un fuseau horaire personnalisé du Centre des États-Unis. Il essaie ensuite de récupérer le fuseau horaire du Centre à partir du Registre. Si l'opération de récupération lève une exception TimeZoneNotFoundException ou InvalidTimeZoneException, le gestionnaire d'exceptions désérialise le fuseau horaire.

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

Stockage et restauration d'une chaîne sérialisée

Dans les exemples précédents, les informations de fuseau horaire ont été stockées dans une variable chaîne puis restaurées. Toutefois, la chaîne qui contient des informations de fuseau horaire sérialisées peut être stockée sur un support de stockage, tel qu'un fichier externe, un fichier de ressources incorporé dans l'application ou le Registre. (Les informations sur les fuseaux horaires personnalisés doivent être stockées à l'écart des clés relatives au fuseau horaire du système dans le Registre.)

En stockant une chaîne de fuseau horaire sérialisée de cette manière, la routine de création de fuseau horaire est également séparée de l'application elle-même. Par exemple, une routine de création de fuseau horaire peut exécuter et créer un fichier de données qui contient des informations de fuseau horaire historiques exploitables par une application. Le fichier de données peut ensuite être installé avec l'application puis être ouvert. Un ou plusieurs de ses fuseaux horaires peuvent être désérialisés dès que l'application en a besoin.

Pour obtenir un exemple qui utilise une ressource incorporée afin de stocker des données de fuseau horaire sérialisées, consultez Comment : enregistrer des fuseaux horaires dans une ressource incorporée et Comment : restaurer des fuseaux horaires dans une ressource incorporée.

Voir aussi

Autres ressources

Heures et fuseaux horaires