Gewusst wie: Speichern von Zeitzonen in einer eingebetteten Ressource
Für eine Anwendung, die Zeitzonen unterstützt, muss häufig eine bestimmte Zeitzone vorhanden sein. Da die Verfügbarkeit einzelner TimeZoneInfo-Objekte jedoch von den Daten abhängt, die in der Registrierung des lokalen Systems gespeichert sind, können selbst normalerweise vorhandene Zeitzonen fehlen. Darüber hinaus werden Daten über benutzerdefinierte Zeitzonen, die mit der CreateCustomTimeZone-Methode instanziiert werden, nicht zusammen mit anderen Zeitzonendaten in der Registrierung gespeichert. Um sicherzustellen, dass diese Zeitzonen zur Verfügung stehen, wenn sie benötigt werden, können Sie sie durch Serialisierung speichern und zu einem späteren Zeitpunkt durch Deserialisierung wiederherstellen.
In der Regel erfolgt die Serialisierung eines TimeZoneInfo-Objekts unabhängig von der Anwendung, die Zeitzonen unterstützt. Je nachdem, welcher Datenspeicher zum Speichern serialisierter TimeZoneInfo-Objekte verwendet wird, werden Zeitzonendaten möglicherweise als Teil einer Einrichtungs- oder Installationsroutine serialisiert (wenn die Daten zum Beispiel in einem Anwendungsschlüssel der Registrierung gespeichert werden) oder als Teil einer Dienstprogrammroutine, die vor dem Kompilieren der endgültigen Anwendung ausgeführt wird (wenn zum Beispiel die serialisierten Daten in einer .NET XML-Ressourcendatei (.resx) gespeichert werden).
Außer einer Ressourcendatei, die zusammen mit der Anwendung kompiliert wird, können zahlreiche weitere Datenspeicher für Zeitzonendaten verwendet werden. Hierzu gehört Folgendes:
Die Registrierung. Beachten Sie, dass eine Anwendung zur Speicherung benutzerdefinierter Zeitzonendaten die Unterschlüssel ihres eigenen Anwendungsschlüssels verwenden sollte, 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 durch Serialisierung in eine RESX-Datei
Rufen Sie eine vorhandene Zeitzone ab, oder erstellen Sie eine neue Zeitzone.
Informationen zum Abrufen einer vorhandenen Zeitzone finden Sie unter Gewusst wie: Zugreifen auf die vordefinierte UTC und lokale Zeitzonenobjekte und Gewusst wie: Instanziieren eines TimeZoneInfo-Objekts.
Rufen Sie zum Erstellen einer neuen Zeitzone eine der Überladungen der CreateCustomTimeZone-Methode auf. Weitere Informationen finden Sie unter Gewusst wie: Erstellen von Zeitzonen ohne Anpassungsregeln und Gewusst wie: Erstellen von Zeitzonen mit Anpassungsregeln.
Rufen Sie die ToSerializedString-Methode auf, um eine Zeichenfolge zu erstellen, die die Daten der Zeitzonen enthält.
Instanziieren Sie ein StreamWriter-Objekt, indem Sie den Namen sowie optional den Pfad zur RESX-Datei des StreamWriter-Klassenkonstruktors angeben.
Instanziieren Sie ein ResXResourceWriter-Objekt, indem Sie das StreamWriter-Objekt an den ResXResourceWriter-Klassenkonstruktor ü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 anhand des Eigenschaftenfensters in Visual Studio sicher, dass für die Buildvorgang-Eigenschaft der RESX-Datei die Option Eingebettete Ressource festgelegt ist.
Beispiel
Im folgenden Beispiel werden ein TimeZoneInfo-Objekt, das Central Normalzeit darstellt, sowie ein TimeZoneInfo-Objekt, das die Zeitzone für Palmer Station in der Antarktis darstellt, in einer .NET XML-Ressourcendatei mit dem Namen SerializedTimeZones.resx serialisiert. Central Normalzeit ist in der Regel in der Registrierung definiert, und bei Palmer Station, Antarktis handelt es sich um eine benutzerdefinierte Zeitzone.
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
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();
}
In diesem Beispiel werden TimeZoneInfo-Objekte serialisiert, damit sie beim Kompilieren in einer Ressourcendatei verfügbar sind.
Da durch die ResXResourceWriter.Generate-Methode vollständige Headerinformationen zu einer .NET XML-Ressourcendatei hinzugefügt werden, kann sie nicht zum Hinzufügen von Ressourcen zu einer vorhandenen Datei verwendet werden. Im Beispiel wird hierbei so verfahren, dass die Datei SerializedTimeZones.resx gesucht wird, und wenn sie vorhanden ist, alle Ressourcen außer den beiden serialisierten Zeitzonen in einem allgemeinen Dictionary<TKey, TValue>-Objekt gespeichert werden. Die vorhandene Datei wird dann gelöscht, und die vorhandenen Ressourcen werden einer neuen SerializedTimeZones.resx-Datei hinzugefügt. Die Daten der serialisierten Zeitzonen werden dieser Datei ebenfalls hinzugefügt.
Die Schlüsselfelder (oder Name) von Ressourcen sollten keine eingebetteten Leerzeichen enthalten. Die Replace(String, String)-Methode wird aufgerufen, um alle eingebetteten Leerzeichen in Zeitzonenbezeichnern zu entfernen, bevor diese der Ressourcendatei zugewiesen werden.
Kompilieren des Codes
Für dieses Beispiel ist Folgendes erforderlich:
Ein Verweis auf System.Windows.Forms.dll und System.Core.dll muss dem Projekt hinzugefügt werden.
Die folgenden Namespaces müssen importiert werden:
Imports System.Globalization Imports System.IO Imports System.Reflection Imports System.Resources
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;
Siehe auch
Aufgaben
Gewusst wie: Wiederherstellen von Zeitzonen aus einer eingebetteten Ressource