Compartir a través de


Cómo: Guardar zonas horarias en un recurso incrustado

Actualización: noviembre 2007

Una aplicación que tiene en cuenta la zona horaria requiere a menudo la presencia de una zona horaria determinada. Sin embargo, como la disponibilidad de objetos TimeZoneInfo individuales depende de la información almacenada en el Registro del sistema local, puede suceder que incluso las zonas horarias personalizadas no se encuentren. Además, la información sobre zonas horarias personalizadas cuya instancia se creó utilizando el método CreateCustomTimeZone no se almacena con otra información sobre zonas horarias en el Registro. Para garantizar que estas zonas horarias estén disponibles cuando se necesiten, puede serializarlas para guardarlas y, después, deserializarlas para restaurarlas.

Normalmente, la serialización de un objeto TimeZoneInfo se realiza de forma separada de la aplicación que tiene en cuenta la zona horaria. Dependiendo del almacén de datos utilizado para contener los objetos TimeZoneInfo serializados, los datos de zona horaria se pueden serializar como parte de una instalación o rutina de instalación (por ejemplo, cuando los datos se almacenan en una clave de aplicación del Registro) o como parte de una rutina de utilidad que se ejecuta antes de que la última aplicación esté compilada (por ejemplo, cuando los datos serializados se almacenan en un archivo de recurso XML (.resx) de .NET).

Además de un archivo de recursos compilado con la aplicación, se pueden usar otros almacenes de datos para información sobre zonas horarias. Se incluyen los siguientes:

  • El Registro. Tenga en cuenta que una aplicación debe utilizar las subclaves de su propia clave de aplicación para almacenar los datos de zonas horarias personalizados en lugar de utilizar las subclaves de HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Time Zones.

  • Archivos de configuración.

  • Otros archivos de sistema.

Para guardar una zona horaria serializándola en un archivo .resx

  1. Recupere una zona horaria existente o cree una zona horaria nueva.

    Para recuperar una zona horaria existente, vea Cómo: Obtener acceso a los objetos de zona horaria local y UTC predefinidos y Cómo: Crear instancias de un objeto TimeZoneInfo.

    Para crear una zona horaria nueva, llame a una de las sobrecargas del método CreateCustomTimeZone. Para obtener más información, vea Cómo: Crear zonas horarias sin reglas de ajuste y Cómo: Crear zonas horarias con reglas de ajuste.

  2. Llame al método ToSerializedString para crear una cadena que contenga los datos de la zona horaria.

  3. Cree instancias de un objeto StreamWriter proporcionando el nombre y, opcionalmente, la ruta de acceso del archivo .resx al constructor de la clase StreamWriter.

  4. Cree instancias de un objeto ResXResourceWriter pasando el objeto StreamWriter al constructor de la clase ResXResourceWriter.

  5. Pase la cadena serializada de la zona horaria al método ResXResourceWriter.AddResource.

  6. Llame al método ResXResourceWriter.Generate.

  7. Llame al método ResXResourceWriter.Close.

  8. Cierre el objeto StreamWriter llamando a su método Close.

  9. Agregue el archivo .resx generado al proyecto de Visual Studio de la aplicación.

  10. Utilice la ventana Propiedades de Visual Studio para asegurarse de que la propiedad Acción de compilación del archivo .resx está establecida en Recurso incrustado.

Ejemplo

En el ejemplo siguiente se serializan un objeto TimeZoneInfo que representa la hora estándar central y un objeto TimeZoneInfo que representa la hora de la Base Palmer, en la Antártida, a un archivo de recursos XML de .NET denominado SerializedTimeZones.resx. Normalmente, la hora estándar central está definida en el Registro; la Base Palmer, en la Antártida, es una zona horaria personalizada.

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();
}

En este ejemplo se serializan objetos TimeZoneInfo para que estén disponibles en un archivo de recursos en tiempo de compilación.

Debido a que el método ResXResourceWriter.Generate agrega la información de encabezado completa a un archivo de recursos XML de .NET, no se puede utilizar para agregar recursos a un archivo existente. En el ejemplo, esto se trata buscando el archivo SerializedTimeZones.resx y, si existe, almacenando todos los recursos que no sean las dos zonas horarias serializadas en un objeto Dictionary<TKey, TValue> genérico. Después, se elimina el archivo existente y los recursos existentes se agregan a un nuevo archivo SerializedTimeZones.resx. Los datos de zona horaria serializada también se agregan a este archivo.

Los campos clave (o Nombre) de los recursos no deben contener espacios incrustados. Se llama al método Replace(String, String) para quitar todos los espacios incrustados en los identificadores de zona horaria antes de asignarlos al archivo de recursos.

Compilar el código

Para este ejemplo se necesita:

  • Que se agregue al proyecto una referencia a System.Windows.Forms.dll y System.Core.dll.

  • Que se importen los siguientes espacios de nombres:

    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;
    

Vea también

Tareas

Cómo: Restaurar zonas horarias de un recurso incrustado

Conceptos

Información general sobre zonas horarias

Otros recursos

Horas y zonas horarias