Partilhar via


Como: Salvar fusos horários em um recurso incorporado

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 individuais TimeZoneInfo depende das informações armazenadas no registro do sistema local, mesmo fusos horários habitualmente disponíveis podem estar ausentes. Além disso, as informações sobre fusos horários personalizados instanciados usando o CreateCustomTimeZone método 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 forem necessários, você pode salvá-los serializando-os e, posteriormente, restaurando-os desserializando-os.

Normalmente, a serialização de um TimeZoneInfo objeto ocorre separadamente do aplicativo com reconhecimento de fuso horário. Dependendo do armazenamento de dados usado para armazenar objetos serializados TimeZoneInfo , os dados de fuso horário podem ser serializados como parte de uma rotina de instalação ou configuraçã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 que é executada antes que o aplicativo final seja compilado (por exemplo, quando os dados serializados são armazenados em um arquivo de recurso .NET XML (.resx)).

Além de um arquivo de recurso que é compilado com o aplicativo, vários outros armazenamentos de dados podem ser usados para informações de fuso horário. Estes incluem:

  • O registo. 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 ficheiros de sistema.

Para salvar um fuso horário serializando-o em um arquivo .resx

  1. Recupere um fuso horário existente ou crie um novo fuso horário.

    Para recuperar um fuso horário existente, consulte Como acessar os objetos UTC e fuso horário local predefinidos e Como instanciar um objeto TimeZoneInfo.

    Para criar um novo fuso horário, chame uma das sobrecargas do CreateCustomTimeZone método. Para obter mais informações, consulte Como criar fusos horários sem regras de ajuste e Como criar fusos horários com regras de ajuste.

  2. Chame o ToSerializedString método para criar uma cadeia de caracteres que contenha os dados do fuso horário.

  3. Instancie um StreamWriter objeto fornecendo o nome e, opcionalmente, o caminho do arquivo .resx para o StreamWriter construtor de classe.

  4. Instancie um ResXResourceWriter objeto passando o StreamWriter objeto para o construtor de ResXResourceWriter classe.

  5. Passe a cadeia de caracteres serializada do fuso horário para o ResXResourceWriter.AddResource método.

  6. Chame o ResXResourceWriter.Generate método.

  7. Chame o ResXResourceWriter.Close método.

  8. Feche o StreamWriter objeto chamando seu Close método.

  9. Adicione o arquivo .resx gerado ao projeto Visual Studio do aplicativo.

  10. Usando a janela Propriedades no Visual Studio, verifique se a propriedade Build Action do arquivo .resx está definida como Embedded Resource.

Exemplo

O exemplo a seguir serializa um TimeZoneInfo objeto que representa a Hora Padrão Central e um TimeZoneInfo objeto que representa a Estação Palmer, hora Antártica para um arquivo de recurso XML .NET chamado SerializedTimeZones.resx. A hora padrão central é normalmente definida no registo; Estação Palmer, Antarctica é 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 TimeZoneInfo objetos para que eles estejam disponíveis em um arquivo de recurso em tempo de compilação.

Como o ResXResourceWriter.Generate método adiciona informações completas de cabeçalho a um arquivo de recurso XML .NET, ele não pode ser usado para adicionar recursos a um arquivo existente. O exemplo lida com isso verificando o arquivo SerializedTimeZones.resx e, se ele existir, armazenando todos os seus recursos diferentes dos dois fusos horários serializados em um objeto genérico Dictionary<TKey,TValue> . O arquivo existente é então excluído e os recursos existentes 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 chave (ou Nome) dos recursos não devem conter espaços incorporados. O Replace(String, String) método é chamado para remover todos os espaços incorporados nos identificadores de fuso horário antes que eles sejam atribuídos ao arquivo de recurso.

Compilação do código

Este exemplo requer:

  • Que uma referência a System.Windows.Forms.dll e System.Core.dll ser acrescentada 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
    

Consulte também