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
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.
Llame al método ToSerializedString para crear una cadena que contenga los datos de la zona horaria.
Cree instancias de un objeto StreamWriter proporcionando el nombre y, opcionalmente, la ruta de acceso del archivo .resx al constructor de la clase StreamWriter.
Cree instancias de un objeto ResXResourceWriter pasando el objeto StreamWriter al constructor de la clase ResXResourceWriter.
Pase la cadena serializada de la zona horaria al método ResXResourceWriter.AddResource.
Llame al método ResXResourceWriter.Generate.
Llame al método ResXResourceWriter.Close.
Cierre el objeto StreamWriter llamando a su método Close.
Agregue el archivo .resx generado al proyecto de Visual Studio de la aplicación.
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