Como: salvar fusos horários em um recurso inserido
Um aplicativo com reconhecimento de fuso horário geralmente requer a presença de um fuso horário específico. No entanto, como a disponibilidade de objetos TimeZoneInfo individuais depende de informações armazenadas no registro do sistema local, até mesmo fusos horários disponíveis normalmente podem estar faltando. Além disso, as informações sobre fusos horários personalizados instanciados usando o método CreateCustomTimeZone não são armazenadas com outras informações de fuso horário no registro. Para garantir que esses fusos horários estejam disponíveis quando necessário, você pode salvá-los serializando-os e restaurá-los posteriormente desserializando-os.
Normalmente, a serialização de um objeto TimeZoneInfo ocorre além do aplicativo com reconhecimento de fuso horário. Dependendo do armazenamento de dados usado para armazenar objetos TimeZoneInfo serializados, os dados de fuso horário podem ser serializados como parte de uma rotina de instalação ou instalação (por exemplo, quando os dados são armazenados em uma chave de aplicativo do Registro) ou como parte de uma rotina de utilitário executada antes da compilação do aplicativo final (por exemplo, quando os dados serializados são armazenados em um arquivo de recurso .NET XML (.resx)).
Além de um arquivo de recurso compilado com o aplicativo, vários outros armazenamentos de dados podem ser usados para informações de fuso horário. Elas incluem o seguinte:
O registro. Observe que um aplicativo deve usar as subchaves de sua própria chave de aplicativo para armazenar dados de fuso horário personalizados em vez de usar as subchaves de HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Time Zones.
Arquivos de configuração.
Outros arquivos do sistema.
Para salvar um fuso horário serializando-o em um arquivo .resx
Recupere um fuso horário ou crie um fuso horário.
Para recuperar um fuso horário, confira Como acessar os objetos de fuso horário utc e local predefinidos e Como criar uma instância de um objeto TimeZoneInfo.
Para criar um fuso horário, chame uma das sobrecargas do método CreateCustomTimeZone. Para mais informações, confira Como criar fusos horários sem regras de ajuste e Como criar fusos horários com regras de ajuste.
Chame o método ToSerializedString para criar uma cadeia de caracteres que contém os dados do fuso horário.
Instancie um objeto StreamWriter fornecendo o nome e, opcionalmente, o caminho do arquivo .resx para o construtor de classe StreamWriter.
Instancie um objeto ResXResourceWriter passando o objeto StreamWriter para o construtor de classe ResXResourceWriter.
Passe a cadeia de caracteres serializada do fuso horário para o método ResXResourceWriter.AddResource.
Chame o método ResXResourceWriter.Generate .
Chame o método ResXResourceWriter.Close .
Feche o objeto StreamWriter chamando seu método Close.
Adicione o arquivo .resx gerado ao projeto do Visual Studio do aplicativo.
Usando a janela Propriedades no Visual Studio, verifique se a propriedade Build Action do arquivo .resx está definida como Recurso Inserido.
Exemplo
O exemplo a seguir serializa um objeto TimeZoneInfo que representa o Horário Padrão Central e um objeto TimeZoneInfo que representa a Estação Palmer, hora da Antártida para um arquivo de recurso XML do .NET chamado SerializedTimeZones.resx. O Horário Padrão Central é normalmente definido no registro; Estação Palmer, Antártida é um fuso horário personalizado.
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
Este exemplo serializa objetos TimeZoneInfo para que eles estejam disponíveis em um arquivo de recurso no tempo de compilação.
Como o método ResXResourceWriter.Generate adiciona informações completas de cabeçalho a um arquivo de recurso .NET XML, ele não pode ser usado para adicionar recursos a um arquivo. O exemplo lida com isso verificando o arquivo SerializedTimeZones.resx e, se existir, armazenando todos os seus recursos além dos dois fusos horários serializados em um objeto genérico Dictionary<TKey,TValue>. O arquivo é então excluído e os recursos são adicionados a um novo arquivo SerializedTimeZones.resx. Os dados de fuso horário serializados também são adicionados a esse arquivo.
Os campos de chave (ou Nome) dos recursos não devem conter espaços inseridos. O método Replace(String, String) é chamado para remover todos os espaços inseridos nos identificadores de fuso horário antes de serem atribuídos ao arquivo de recurso.
Compilando o código
Este exemplo requer:
Que uma referência a System.Windows.Forms.dll e System.Core.dll seja adicionada ao projeto.
Que os seguintes namespaces sejam importados:
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