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

  1. 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.

  2. Rufen Sie die ToSerializedString-Methode auf, um eine Zeichenfolge zu erstellen, die die Daten der Zeitzone enthält.

  3. Instanziieren Sie ein StreamWriter-Objekt, indem Sie den Namen und optional den Pfad der RESX-Datei zum Konstruktor der StreamWriter-Klasse angeben.

  4. Instanziieren Sie ein ResXResourceWriter-Objekt, indem Sie das StreamWriter-Objekt an den Konstruktor der ResXResourceWriter-Klasse übergeben.

  5. Übergeben Sie die serialisierte Zeichenfolge der Zeitzone an die ResXResourceWriter.AddResource-Methode.

  6. Rufen Sie die ResXResourceWriter.Generate-Methode auf.

  7. Rufen Sie die ResXResourceWriter.Close-Methode auf.

  8. Schließen Sie das StreamWriter-Objekt, indem Sie seine Close-Methode aufrufen.

  9. Fügen Sie die generierte RESX-Datei dem Visual Studio-Projekt der Anwendung hinzu.

  10. 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
    

Weitere Informationen