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
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.
Appelez la méthode ToSerializedString pour créer une chaîne qui contient les données du fuseau horaire.
Instanciez un objet StreamWriter en fournissant le nom du fichier .resx, et éventuellement son chemin, au constructeur de classe StreamWriter.
Instanciez un objet ResXResourceWriter en passant l’objet StreamWriter au constructeur de classe ResXResourceWriter.
Passez la chaîne sérialisée du fuseau horaire à la méthode ResXResourceWriter.AddResource.
Appelez la méthode ResXResourceWriter.Generate .
Appelez la méthode ResXResourceWriter.Close .
Fermez l’objet StreamWriter en appelant sa méthode Close.
Ajoutez le fichier .resx généré au projet Visual Studio de l’application.
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