Partager via


Procédure : enregistrer des fuseaux horaires dans une ressource incorporée

Une application dépendante des fuseaux horaires nécessite souvent la présence d’un fuseau horaire particulier. Toutefois, comme la disponibilité des objets TimeZoneInfo individuels varie en fonction des informations stockées dans le Registre du système local, même des fuseaux horaires habituellement disponibles peuvent être absents. Par ailleurs, les informations sur les fuseaux horaires personnalisés qui ont été instanciés avec la méthode CreateCustomTimeZone ne sont pas stockées avec les autres informations de fuseau horaire dans le Registre. Pour vous assurer que ces fuseaux horaires sont disponibles quand ils sont nécessaires, vous pouvez les enregistrer en les sérialisant, puis les restaurer ultérieurement en les désérialisant.

En règle générale, la sérialisation d’un objet TimeZoneInfo se produit en dehors de l’application dépendante des fuseaux horaires. Selon le magasin de données utilisé pour stocker les objets TimeZoneInfo sérialisés, les données de fuseau horaire peuvent être sérialisées dans le cadre d’une routine d’installation (par exemple, quand les données sont stockées dans une clé d’application du Registre) ou dans le cadre d’une routine utilitaire qui s’exécute avant la compilation de l’application finale (par exemple, lorsque les données sérialisées sont stockées dans un fichier de ressources XML (.resx) .NET.

En plus d’un fichier de ressources compilé avec l’application, plusieurs autres magasins de données peuvent être utilisés pour les informations de fuseau horaire. Leurs thèmes sont les suivants :

  • Le Registre. Notez qu’une application doit utiliser les sous-clés de sa propre clé d’application pour stocker des données de fuseau horaire personnalisé au lieu d’utiliser les sous-clés de HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Time Zones.

  • Fichiers de configuration.

  • Autres fichiers système.

Pour enregistrer un fuseau horaire en le sérialisant dans un fichier .resx

  1. Récupérez un fuseau horaire existant ou créez un autre fuseau horaire.

    Pour récupérer un fuseau horaire existant, consultez Guide pratique pour accéder aux objets UTC et aux objets de fuseau horaire local prédéfinis et Guide pratique pour instancier un objet TimeZoneInfo.

    Pour créer un autre fuseau horaire, appelez l’une des surcharges de la méthode CreateCustomTimeZone. Pour plus d’informations, consultez Guide pratique pour créer des fuseaux horaires sans règles d’ajustement et Guide pratique pour créer des fuseaux horaires avec des règles d’ajustement.

  2. Appelez la méthode ToSerializedString pour créer une chaîne qui contient les données du fuseau horaire.

  3. Instanciez un objet StreamWriter en fournissant le nom du fichier .resx, et éventuellement son chemin, au constructeur de classe StreamWriter.

  4. Instanciez un objet ResXResourceWriter en passant l’objet StreamWriter au constructeur de classe ResXResourceWriter.

  5. Passez la chaîne sérialisée du fuseau horaire à la méthode ResXResourceWriter.AddResource.

  6. Appelez la méthode ResXResourceWriter.Generate .

  7. Appelez la méthode ResXResourceWriter.Close .

  8. Fermez l’objet StreamWriter en appelant sa méthode Close.

  9. Ajoutez le fichier .resx généré au projet Visual Studio de l’application.

  10. Dans la fenêtre Propriétés de Visual Studio, vérifiez que la propriété Build Action (Action de build) dans le fichier .resx est définie sur Embedded Resource (Ressource incorporée).

Exemple

L’exemple suivant sérialise deux objets dans un fichier de ressources XML .NET nommé SerializedTimeZones.resx : l’objet TimeZoneInfo qui représente le fuseau horaire Centre et l’objet TimeZoneInfo qui représente le fuseau horaire Station Palmer, Antarctique. Le fuseau horaire Centre est généralement défini dans le Registre, et le fuseau horaire Station Palmer, Antarctique est un fuseau horaire personnalisé.

TimeZoneSerialization()
{
   TextWriter writeStream;
   Dictionary<string, string> resources = new Dictionary<string, string>();
   // Determine if .resx file exists
   if (File.Exists(resxName))
   {
      // Open reader
      TextReader readStream = new StreamReader(resxName);
      ResXResourceReader resReader = new ResXResourceReader(readStream);
      foreach (DictionaryEntry item in resReader)
      {
         if (! (((string) item.Key) == "CentralStandardTime" ||
                ((string) item.Key) == "PalmerStandardTime" ))
            resources.Add((string)item.Key, (string) item.Value);
      }
      readStream.Close();
      // Delete file, since write method creates duplicate xml headers
      File.Delete(resxName);
   }

   // Open stream to write to .resx file
   try
   {
      writeStream = new StreamWriter(resxName, true);
   }
   catch (FileNotFoundException e)
   {
      // Handle failure to find file
      Console.WriteLine("{0}: The file {1} could not be found.", e.GetType().Name, resxName);
      return;
   }

   // Get resource writer
   ResXResourceWriter resWriter = new ResXResourceWriter(writeStream);

   // Add resources from existing file
   foreach (KeyValuePair<string, string> item in resources)
   {
      resWriter.AddResource(item.Key, item.Value);
   }

   // Serialize Central Standard Time
   try
   {
      TimeZoneInfo cst = TimeZoneInfo.FindSystemTimeZoneById("Central Standard Time");
      resWriter.AddResource(cst.Id.Replace(" ", string.Empty), cst.ToSerializedString());
   }
   catch (TimeZoneNotFoundException)
   {
      Console.WriteLine("The Central Standard Time zone could not be found.");
   }

   // Create time zone for Palmer, Antarctica
   //
   // Define transition times to/from DST
   TimeZoneInfo.TransitionTime startTransition = TimeZoneInfo.TransitionTime.CreateFloatingDateRule(new DateTime(1, 1, 1, 4, 0, 0),
                                                                                              10, 2, DayOfWeek.Sunday);
   TimeZoneInfo.TransitionTime endTransition = TimeZoneInfo.TransitionTime.CreateFloatingDateRule(new DateTime(1, 1, 1, 3, 0, 0),
                                                                                            3, 2, DayOfWeek.Sunday);
   // Define adjustment rule
   TimeSpan delta = new TimeSpan(1, 0, 0);
   TimeZoneInfo.AdjustmentRule adjustment = TimeZoneInfo.AdjustmentRule.CreateAdjustmentRule(new DateTime(1999, 10, 1),
                                         DateTime.MaxValue.Date, delta, startTransition, endTransition);
   // Create array for adjustment rules
   TimeZoneInfo.AdjustmentRule[] adjustments = {adjustment};
   // Define other custom time zone arguments
   string DisplayName = "(GMT-04:00) Antarctica/Palmer Time";
   string standardName = "Palmer Standard Time";
   string daylightName = "Palmer Daylight Time";
   TimeSpan offset = new TimeSpan(-4, 0, 0);
   TimeZoneInfo palmer = TimeZoneInfo.CreateCustomTimeZone(standardName, offset, DisplayName, standardName, daylightName, adjustments);
   resWriter.AddResource(palmer.Id.Replace(" ", String.Empty), palmer.ToSerializedString());

   // Save changes to .resx file
   resWriter.Generate();
   resWriter.Close();
   writeStream.Close();
}
Private Sub SerializeTimeZones()
    Dim writeStream As TextWriter
    Dim resources As New Dictionary(Of String, String)
    ' Determine if .resx file exists
    If File.Exists(resxName) Then
        ' Open reader
        Dim readStream As TextReader = New StreamReader(resxName)
        Dim resReader As New ResXResourceReader(readStream)
        For Each item As DictionaryEntry In resReader
            If Not (CStr(item.Key) = "CentralStandardTime" Or _
                    CStr(item.Key) = "PalmerStandardTime") Then
                resources.Add(CStr(item.Key), CStr(item.Value))
            End If
        Next
        readStream.Close()
        ' Delete file, since write method creates duplicate xml headers
        File.Delete(resxName)
    End If

    ' Open stream to write to .resx file
    Try
        writeStream = New StreamWriter(resxName, True)
    Catch e As FileNotFoundException
        ' Handle failure to find file
        Console.WriteLine("{0}: The file {1} could not be found.", e.GetType().Name, resxName)
        Exit Sub
    End Try

    ' Get resource writer
    Dim resWriter As ResXResourceWriter = New ResXResourceWriter(writeStream)

    ' Add resources from existing file
    For Each item As KeyValuePair(Of String, String) In resources
        resWriter.AddResource(item.Key, item.Value)
    Next
    ' Serialize Central Standard Time
    Try
        Dim cst As TimeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById("Central Standard Time")
        resWriter.AddResource(cst.Id.Replace(" ", String.Empty), cst.ToSerializedString())
    Catch
        Console.WriteLine("The Central Standard Time zone could not be found.")
    End Try

    ' Create time zone for Palmer, Antarctica
    '
    ' Define transition times to/from DST
    Dim startTransition As TimeZoneInfo.TransitionTime = TimeZoneInfo.TransitionTime.CreateFloatingDateRule(#4:00:00 AM#, 10, 2, DayOfWeek.Sunday)
    Dim endTransition As TimeZoneInfo.TransitionTime = TimeZoneInfo.TransitionTime.CreateFloatingDateRule(#3:00:00 AM#, 3, 2, DayOfWeek.Sunday)
    ' Define adjustment rule
    Dim delta As TimeSpan = New TimeSpan(1, 0, 0)
    Dim adjustment As TimeZoneInfo.AdjustmentRule = TimeZoneInfo.AdjustmentRule.CreateAdjustmentRule(#10/1/1999#, Date.MaxValue.Date, delta, startTransition, endTransition)
    ' Create array for adjustment rules
    Dim adjustments() As TimeZoneInfo.AdjustmentRule = {adjustment}
    ' Define other custom time zone arguments
    Dim DisplayName As String = "(GMT-04:00) Antarctica/Palmer Time"
    Dim standardName As String = "Palmer Standard Time"
    Dim daylightName As String = "Palmer Daylight Time"
    Dim offset As TimeSpan = New TimeSpan(-4, 0, 0)
    Dim palmer As TimeZoneInfo = TimeZoneInfo.CreateCustomTimeZone(standardName, offset, DisplayName, standardName, daylightName, adjustments)
    resWriter.AddResource(palmer.Id.Replace(" ", String.Empty), palmer.ToSerializedString())

    ' Save changes to .resx file 
    resWriter.Generate()
    resWriter.Close()
    writeStream.Close()
End Sub

Cet exemple sérialise les objets TimeZoneInfo dans un fichier de ressources afin de les rendre disponibles au moment de la compilation.

Étant donné que la méthode ResXResourceWriter.Generate ajoute des informations d’en-tête complètes à un fichier de ressources XML .NET, elle ne peut pas être utilisée pour ajouter des ressources à un fichier existant. Pour gérer cela, l’exemple recherche le fichier SerializedTimeZones.resx et, s’il le trouve, il stocke toutes ses ressources, à l’exception des deux fuseaux horaires sérialisés, dans un objet Dictionary<TKey,TValue> générique. Le fichier existant est ensuite supprimé, puis les ressources existantes sont ajoutées à un nouveau fichier SerializedTimeZones.resx. Les données de fuseau horaire sérialisé sont également ajoutées à ce fichier.

Les champs de clé (ou de nom) des ressources ne doivent pas contenir d’espaces incorporés. La méthode Replace(String, String) est appelée pour supprimer tous les espaces incorporés dans les identificateurs de fuseau horaire avant leur affectation au fichier de ressources.

Compilation du code

Cet exemple nécessite :

  • L’ajout d’une référence à System.Windows.Forms.dll et à System.Core.dll dans le projet.

  • L’importation des espaces de noms suivants :

    using System;
    using System.Collections;
    using System.Collections.Generic;
    using System.Globalization;
    using System.IO;
    using System.Reflection;
    using System.Resources;
    using System.Windows.Forms;
    
    Imports System.Globalization
    Imports System.IO
    Imports System.Reflection
    Imports System.Resources
    

Voir aussi