Vorgehensweise: Speichern von Zeitzonen in einer eingebetteten Ressource
Eine zeitzonenfähige Anwendung erfordert häufig das Vorhandensein einer bestimmten Zeitzone. Da die Verfügbarkeit einzelner TimeZoneInfo-Objekte jedoch von Informationen abhängt, die in der Registrierung des lokalen Systems gespeichert sind, kann es vorkommen, dass sogar üblicherweise verfügbare Zeitzonen nicht vorhanden sind. Außerdem werden Informationen zu benutzerdefinierten Zeitzonen, die mit der CreateCustomTimeZone-Methode instanziiert wurden, nicht zusammen mit anderen Zeitzoneninformationen in der Registrierung gespeichert. Um sicherzustellen, dass diese Zeitzonen bei Bedarf verfügbar sind, können Sie sie speichern, indem Sie sie serialisieren und später durch Deserialisieren wiederherstellen.
In der Regel erfolgt das Serialisieren eines TimeZoneInfo-Objekts unabhängig von der zeitzonenfähigen Anwendung. Abhängig vom Datenspeicher, der für die Speicherung serialisierter TimeZoneInfo Objekte verwendet wird, können Zeitzonendaten als Teil einer Setup- oder Installationsroutine serialisiert werden (z. B. wenn die Daten in einem Anwendungsschlüssel der Registrierung gespeichert werden) oder als Teil einer Hilfsroutine, die vor der Kompilierung der endgültigen Anwendung ausgeführt wird (z. B. wenn die serialisierten Daten in einer .NET-XML-Ressourcendatei (RESX-Datei) gespeichert werden).
Zusätzlich zu einer Ressourcendatei, die mit der Anwendung kompiliert wird, können mehrere andere Datenspeicher für Zeitzoneninformationen verwendet werden. Diese umfassen die folgenden Themen:
Die Registrierung. Beachten Sie, dass eine Anwendung die Unterschlüssel ihres eigenen Anwendungsschlüssels verwenden sollte, um benutzerdefinierte Zeitzonendaten zu speichern, anstatt die Unterschlüssel von HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Time Zones zu verwenden.
Konfigurationsdateien:
Andere Systemdateien.
So speichern Sie eine Zeitzone, indem Sie sie in eine RESX-Datei serialisieren
Rufen Sie eine vorhandene Zeitzone ab, oder erstellen Sie eine neue Zeitzone.
Informationen zum Abrufen einer vorhandenen Zeitzone finden Sie unter Vorgehensweise: Zugreifen auf vordefinierte UTC- und lokale Zeitzonenobjekte und Vorgehensweise: Instanziieren eines TimeZoneInfo-Objekts.
Um eine neue Zeitzone zu erstellen, rufen Sie eine der Überladungen der CreateCustomTimeZone-Methode auf. Weitere Informationen finden Sie unter Vorgehensweise: Erstellen von Zeitzonenn ohne Anpassungsregeln und Vorgehensweise: Erstellen von Zeitzonen mit Anpassungsregeln.
Rufen Sie die ToSerializedString-Methode auf, um eine Zeichenfolge zu erstellen, die die Daten der Zeitzone enthält.
Instanziieren Sie ein StreamWriter-Objekt, indem Sie den Namen und optional den Pfad der RESX-Datei zum Konstruktor der StreamWriter-Klasse angeben.
Instanziieren Sie ein ResXResourceWriter-Objekt, indem Sie das StreamWriter-Objekt an den Konstruktor der ResXResourceWriter-Klasse übergeben.
Übergeben Sie die serialisierte Zeichenfolge der Zeitzone an die ResXResourceWriter.AddResource-Methode.
Rufen Sie die ResXResourceWriter.Generate-Methode auf.
Rufen Sie die ResXResourceWriter.Close-Methode auf.
Schließen Sie das StreamWriter-Objekt, indem Sie seine Close-Methode aufrufen.
Fügen Sie die generierte RESX-Datei dem Visual Studio-Projekt der Anwendung hinzu.
Stellen Sie im Fenster Eigenschaften in Visual Studio sicher, dass die Buildaktion-Eigenschaft der RESX-Datei auf Eingebettete Ressource festgelegt ist.
Beispiel
Im folgenden Beispiel werden ein TimeZoneInfo-Objekt, das die Zeitzone „Central Standard Time“ darstellt, und ein TimeZoneInfo-Objekt, das die Zeitzone „Palmer Station, Antarctica“ darstellt, in eine .NET-XML-Ressourcendatei mit dem Namen „SerializedTimeZones.resx“ serialisiert. „Central Standard Time“ wird in der Regel in der Registrierung definiert. „Palmer Station, Antarctica“ ist eine benutzerdefinierte Zeitzone.
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
In diesem Beispiel werden TimeZoneInfo-Objekte serialisiert, sodass sie zur Kompilierzeit in einer Ressourcendatei verfügbar sind.
Da die ResXResourceWriter.Generate-Methode einer .NET-XML-Ressourcendatei vollständige Headerinformationen hinzufügt, kann sie nicht zum Hinzufügen von Ressourcen zu einer vorhandenen Datei verwendet werden. Im Beispiel wird zu diesem Zweck überprüft, ob die Datei „SerializedTimeZones.resx“ vorhanden ist. Wenn dies der Fall ist, werden alle Ressourcen außer den beiden serialisierten Zeitzonen in einem generischen Dictionary<TKey,TValue>-Objekt gespeichert. Die vorhandene Datei wird dann gelöscht, und die vorhandenen Ressourcen werden einer neuen Datei „SerializedTimeZones.resx“ hinzugefügt. Die serialisierten Zeitzonendaten werden dieser Datei ebenfalls hinzugefügt.
Die Schlüsselfelder (oder Namen-Felder) von Ressourcen dürfen keine eingebetteten Leerzeichen enthalten. Die Replace(String, String)-Methode wird aufgerufen, um alle eingebetteten Leerzeichen in den Zeitzonenbezeichnern zu entfernen, bevor sie der Ressourcendatei zugewiesen werden.
Kompilieren des Codes
Für dieses Beispiel benötigen Sie Folgendes:
Dass dem Projekt ein Verweis auf „System.Windows.Forms.dll“ und „System.Core.dll“ hinzugefügt wird.
Dass die folgenden Namespaces importiert werden:
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