Condividi tramite


Salvataggio e ripristino dei fusi orari

Aggiornamento: novembre 2007

La classe TimeZoneInfo si basa sul Registro di sistema per recuperare i dati predefiniti del fuso orario, sebbene il Registro di sistema sia una struttura dinamica. Inoltre, le informazioni del fuso orario contenute nel Registro di sistema vengono utilizzate dal sistema operativo principalmente per gestire le regolazioni e le conversioni di fusi orari per l'anno corrente. Ciò comporta due principali implicazioni per le applicazioni che si basano su dati del fuso orario accurati:

  • È possibile che un fuso orario richiesto da un'applicazione non sia definito nel Registro di sistema o che sia stato rinominato o rimosso dal Registro di sistema.

  • È possibile che un fuso orario definito nel Registro di sistema non contenga le informazioni su determinate regole di regolazione necessarie per le conversioni di fusi orari storici.

La classe TimeZoneInfo risolve tali limitazioni grazie al supporto della serializzazione (salvataggio) e della deserializzazione (ripristino) dei dati del fuso orario.

Serializzazione e deserializzazione del fuso orario

Il salvataggio e il ripristino di un fuso orario serializzando e deserializzando i dati del fuso orario comportano solo due chiamate al metodo:

  • È possibile serializzare un oggetto TimeZoneInfo chiamando il metodo ToSerializedString di tale oggetto. Il metodo non accetta alcun parametro e restituisce una stringa che contiene le informazioni del fuso orario.

  • È possibile deserializzare un oggetto TimeZoneInfo da una stringa serializzata passando tale stringa al metodo static (Shared in Visual Basic) TimeZoneInfo.FromSerializedString.

Scenari di serializzazione e deserializzazione

La possibilità di salvare (o serializzare) un oggetto TimeZoneInfo in una stringa e di ripristinarlo (o deserializzarlo) per un uso successivo aumenta l'utilità e la flessibilità della classe TimeZoneInfo. In questa sezione vengono esaminate alcune situazioni in cui la serializzazione e la deserializzazione sono molto utili.

Serializzazione e deserializzazione dei dati del fuso orario in un'applicazione

Un fuso orario serializzato può essere ripristinato da una stringa quando necessario. Tale operazione potrebbe risultare necessaria quando il fuso orario recuperato dal Registro di sistema non è in grado di convertire correttamente una data e ora all'interno di un determinato intervallo di date. Ad esempio, i dati del fuso orario nel Registro di sistema di Windows XP supportano una sola regola di regolazione, mentre i fusi orari definiti nel Registro di sistema di Windows Vista forniscono generalmente informazioni su due regole di regolazione. Ciò significa che le conversioni di fusi orari storici potrebbero essere imprecise. La serializzazione e la deserializzazione dei dati del fuso orario possono gestire tale limitazione.

Nell'esempio seguente viene definita una classe TimeZoneInfo personalizzata senza regole di regolazione per rappresentare il fuso Ora solare USA Orientale dal 1883 al 1917, prima dell'introduzione dell'ora legale negli Stati Uniti. Il fuso orario personalizzato viene serializzato in una variabile con ambito globale. L'ora UTC viene passata al metodo di conversione del fuso orario, ConvertUtcTime, per essere convertita. Se la data e l'ora rientrano nel 1917 o in un anno precedente, il fuso Ora solare orientale personalizzato viene ripristinato da una stringa serializzata e sostituisce il fuso orario recuperato dal Registro di sistema.

Module TimeZoneSerialization
   Dim serializedEst As String

   Public Sub Main()
      ' Retrieve Eastern Standard Time zone from registry
      Try
         Dim est As TimeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById("Eastern Standard Time")
         ' Create custom Eastern Time Zone for historical (pre-1918) conversions
         CreateTimeZone()
         ' Call conversion function with one current and one pre-1918 date and time
         Console.WriteLine(ConvertUtcTime(Date.UtcNow, est))
         Console.WriteLine(ConvertUtcTime(New Date(1900, 11, 15, 9, 32, 00, DateTimeKind.Utc), est))
      Catch e As TimeZoneNotFoundException
         Console.WriteLine("The Eastern Standard Time zone is not in the registry.")
      Catch e As InvalidTimeZoneException
         Console.WriteLine("Data on the Eastern Standard Time Zone in the registry is corrupted.")
      End Try   
   End Sub

   Private Sub CreateTimeZone()
      ' Create a simple Eastern Standard time zone 
      ' without adjustment rules for 1883-1918
      Dim earlyEstZone As TimeZoneInfo = TimeZoneInfo.CreateCustomTimeZone("Eastern Standard Time", _
                                      New TimeSpan(-5, 0, 0), _
                                      " (GMT-05:00) Eastern Time (United States)", _ 
                                      "Eastern Standard Time")
      serializedEst = earlyEstZone.ToSerializedString()                                
   End Sub

   Private Function ConvertUtcTime(utcDate As Date, tz As TimeZoneInfo) As Date
      ' Use time zone object from registry 
      If Year(utcDate) > 1917 Then
         Return TimeZoneInfo.ConvertTimeFromUtc(utcDate, tz)
      ' Handle dates before introduction of DST
      Else
         ' Restore serialized time zone object
         tz = TimeZoneInfo.FromSerializedString(serializedEst)
         Return TimeZoneInfo.ConvertTimeFromUtc(utcDate, tz)
      End If      
   End Function
End Module
using System;

public class TimeZoneSerialization
{
   static string serializedEst;

   public static void Main()
   {
      // Retrieve Eastern Standard Time zone from registry
      try
      {
         TimeZoneSerialization tzs = new TimeZoneSerialization();
         TimeZoneInfo est = TimeZoneInfo.FindSystemTimeZoneById("Eastern Standard Time");
         // Create custom Eastern Time Zone for historical (pre-1918) conversions
         CreateTimeZone();
         // Call conversion function with one current and one pre-1918 date and time
         Console.WriteLine(ConvertUtcTime(DateTime.UtcNow, est));
         Console.WriteLine(ConvertUtcTime(new DateTime(1900, 11, 15, 9, 32, 00, DateTimeKind.Utc), est));
      }
      catch (TimeZoneNotFoundException)
      {
         Console.WriteLine("The Eastern Standard Time zone is not in the registry.");
      }
      catch (InvalidTimeZoneException)
      {
         Console.WriteLine("Data on the Eastern Standard Time Zone in the registry is corrupted.");
      }   
   }

   private static void CreateTimeZone()
   {
      // Create a simple Eastern Standard time zone 
      // without adjustment rules for 1883-1918
      TimeZoneInfo earlyEstZone = TimeZoneInfo.CreateCustomTimeZone("Eastern Standard Time", 
                                      new TimeSpan(-5, 0, 0), 
                                      " (GMT-05:00) Eastern Time (United States)",  
                                      "Eastern Standard Time");
      serializedEst = earlyEstZone.ToSerializedString();                        
   }

   private static DateTime ConvertUtcTime(DateTime utcDate, TimeZoneInfo tz) 
   {
      // Use time zone object from registry 
      if (utcDate.Year > 1917)
      {
         return TimeZoneInfo.ConvertTimeFromUtc(utcDate, tz);
      }   
      // Handle dates before introduction of DST
      else
      {
         // Restore serialized time zone object
         tz = TimeZoneInfo.FromSerializedString(serializedEst);
         return TimeZoneInfo.ConvertTimeFromUtc(utcDate, tz);
      }      
   }
}

Gestione delle eccezioni del fuso orario

Poiché il Registro di sistema è una struttura dinamica, il contenuto è soggetto a modifiche accidentali o intenzionali, ovvero è possibile che un fuso orario, che dovrebbe essere definito nel Registro di sistema e necessario per la corretta esecuzione di un'applicazione, sia assente. Senza il supporto della serializzazione e della deserializzazione del fuso orario non si ha altra scelta che terminare l'applicazione per gestire l'eccezione TimeZoneNotFoundException. Grazie alla serializzazione e alla deserializzazione del fuso orario è, tuttavia, possibile gestire un'eccezione TimeZoneNotFoundException imprevista ripristinando il fuso orario necessario da una stringa serializzata in modo da poter continuare l'esecuzione dell'applicazione.

Nell'esempio seguente viene creato e serializzato un fuso Ora solare fuso centrale personalizzato. Viene poi effettuato un tentativo di recuperare il fuso Ora solare fuso centrale dal Registro di sistema. Se l'operazione di recupero genera un'eccezione TimeZoneNotFoundException o un'eccezione InvalidTimeZoneException, il gestore di eccezioni deserializza il fuso orario.

Imports System.Collections.Generic

Public Class TimeZoneApplication
   ' Define collection of custom time zones
   Private customTimeZones As New Dictionary(Of String, String)
   Private cst As TimeZoneInfo 

   Public Sub New()
      ' Define custom Central Standard Time
      '
      ' Declare necessary TimeZoneInfo.AdjustmentRule objects for time zone
      Dim customTimeZone As TimeZoneInfo
      Dim delta As New TimeSpan(1, 0, 0)
      Dim adjustment As TimeZoneInfo.AdjustmentRule
      Dim adjustmentList As New List(Of TimeZoneInfo.AdjustmentRule)
      ' Declare transition time variables to hold transition time information
      Dim transitionRuleStart, transitionRuleEnd As TimeZoneInfo.TransitionTime

      ' Define end rule (for 1976-2006)
      transitionRuleEnd = TimeZoneInfo.TransitionTime.CreateFloatingDateRule(#02:00:00AM#, 10, 5, DayOfWeek.Sunday)
      ' Define rule (1976-1986)
      transitionRuleStart = TimeZoneInfo.TransitionTime.CreateFloatingDateRule(#2:00:00AM#, 04, 05, DayOfWeek.Sunday)
      adjustment = TimeZoneInfo.AdjustmentRule.CreateAdjustmentRule(#01/01/1976#, #12/31/1986#, delta, transitionRuleStart, transitionRuleEnd)
      adjustmentList.Add(adjustment)
      ' Define rule (1987-2006)  
      transitionRuleStart = TimeZoneInfo.TransitionTime.CreateFloatingDateRule(#2:00:00AM#, 04, 01, DayOfWeek.Sunday)
      adjustment = TimeZoneInfo.AdjustmentRule.CreateAdjustmentRule(#01/01/1987#, #12/31/2006#, delta, transitionRuleStart, transitionRuleEnd)
      adjustmentList.Add(adjustment)
      ' Define rule (2007- )  
      transitionRuleStart = TimeZoneInfo.TransitionTime.CreateFloatingDateRule(#2:00:00AM#, 03, 02, DayOfWeek.Sunday)
      transitionRuleEnd = TimeZoneInfo.TransitionTime.CreateFloatingDateRule(#2:00:00AM#, 11, 01, DayOfWeek.Sunday)
      adjustment = TimeZoneInfo.AdjustmentRule.CreateAdjustmentRule(#01/01/2007#, Date.MaxValue.Date, delta, transitionRuleStart, transitionRuleEnd)
      adjustmentList.Add(adjustment)
      ' Create custom time zone
      customTimeZone = TimeZoneInfo.CreateCustomTimeZone("Central Standard Time", _
                      New TimeSpan(-6, 0, 0), _
                      "(GMT-06:00) Central Time (US Only)", "Central Standard Time", _
                      "Central Daylight Time", adjustmentList.ToArray())
      ' Add time zone to collection
      customTimeZones.Add(customTimeZone.Id, customTimeZone.ToSerializedString())                           

      ' Create any other required time zones     
   End Sub

   Public Shared Sub Main()
      Dim tza As New TimeZoneApplication()
      tza.AppEntryPoint()
   End Sub

   Private Sub AppEntryPoint()
      Try
         cst = TimeZoneInfo.FindSystemTimeZoneById("Central Standard Time")
      Catch e As TimeZoneNotFoundException
         If customTimeZones.ContainsKey("Central Standard Time")
            HandleTimeZoneException("Central Standard Time")
         End If
      Catch e As InvalidTimeZoneException
         If customTimeZones.ContainsKey("Central Standard Time")
            HandleTimeZoneException("Central Standard Time")
         End If
      End Try               
      If cst Is Nothing Then
         Console.WriteLine("Unable to load Central Standard Time zone.")
         Return
      End If
      Dim currentTime As Date = Date.Now
      Console.WriteLine("The current {0} time is {1}.", _
                        IIf(TimeZoneInfo.Local.IsDaylightSavingTime(currentTime), _
                            TimeZoneInfo.Local.StandardName, _
                            TimeZoneInfo.Local.DaylightName), _
                        currentTime.ToString("f"))
      Console.WriteLine("The current {0} time is {1}.", _
                        IIf(cst.IsDaylightSavingTime(currentTime), _
                            cst.StandardName, _
                            cst.DaylightName), _
                        TimeZoneInfo.ConvertTime(currentTime, TimeZoneInfo.Local, cst).ToString("f"))
   End Sub

   Private Sub HandleTimeZoneException(timeZoneName As String)
      Dim tzString As String = customTimeZones.Item(timeZoneName)
      cst = TimeZoneInfo.FromSerializedString(tzString)
   End Sub
End Class
using System;
using System.Collections.Generic;

public class TimeZoneApplication
{
   // Define collection of custom time zones
   private Dictionary<string, string> customTimeZones = new Dictionary<string, string>();
   private TimeZoneInfo cst;

   public TimeZoneApplication()
   {
      // Create custom Central Standard Time 
      //
      // Declare necessary TimeZoneInfo.AdjustmentRule objects for time zone
      TimeZoneInfo customTimeZone;
      TimeSpan delta = new TimeSpan(1, 0, 0);
      TimeZoneInfo.AdjustmentRule adjustment;
      List<TimeZoneInfo.AdjustmentRule> adjustmentList = new List<TimeZoneInfo.AdjustmentRule>();
      // Declare transition time variables to hold transition time information
      TimeZoneInfo.TransitionTime transitionRuleStart, transitionRuleEnd;

      // Define end rule (for 1976-2006)
      transitionRuleEnd = TimeZoneInfo.TransitionTime.CreateFloatingDateRule(new DateTime(1, 1, 1, 2, 0, 0), 10, 5, DayOfWeek.Sunday);
      // Define rule (1976-1986)
      transitionRuleStart = TimeZoneInfo.TransitionTime.CreateFloatingDateRule(new DateTime(1, 1, 1, 2, 0, 0), 04, 05, DayOfWeek.Sunday);
      adjustment = TimeZoneInfo.AdjustmentRule.CreateAdjustmentRule(new DateTime(1976, 1, 1), new DateTime(1986, 12, 31), delta, transitionRuleStart, transitionRuleEnd);
      adjustmentList.Add(adjustment);
      // Define rule (1987-2006)  
      transitionRuleStart = TimeZoneInfo.TransitionTime.CreateFloatingDateRule(new DateTime(1, 1, 1, 2, 0, 0), 04, 01, DayOfWeek.Sunday);
      adjustment = TimeZoneInfo.AdjustmentRule.CreateAdjustmentRule(new DateTime(1987, 1, 1), new DateTime(2006, 12, 31), delta, transitionRuleStart, transitionRuleEnd);
      adjustmentList.Add(adjustment);
      // Define rule (2007- )  
      transitionRuleStart = TimeZoneInfo.TransitionTime.CreateFloatingDateRule(new DateTime(1, 1, 1, 2, 0, 0), 03, 02, DayOfWeek.Sunday);
      transitionRuleEnd = TimeZoneInfo.TransitionTime.CreateFloatingDateRule(new DateTime(1, 1, 1, 2, 0, 0), 11, 01, DayOfWeek.Sunday);
      adjustment = TimeZoneInfo.AdjustmentRule.CreateAdjustmentRule(new DateTime(2007, 01, 01), DateTime.MaxValue.Date, delta, transitionRuleStart, transitionRuleEnd);
      adjustmentList.Add(adjustment);

      // Create custom U.S. Central Standard Time zone         
      customTimeZone = TimeZoneInfo.CreateCustomTimeZone("Central Standard Time", 
                      new TimeSpan(-6, 0, 0), 
                      "(GMT-06:00) Central Time (US Only)", "Central Standard Time", 
                      "Central Daylight Time", adjustmentList.ToArray());       
      // Add time zone to collection
      customTimeZones.Add(customTimeZone.Id, customTimeZone.ToSerializedString());                           

      // Create any other required time zones     
   }

   public static void Main()
   {
      TimeZoneApplication tza = new TimeZoneApplication();
      tza.AppEntryPoint();
   }

   private void AppEntryPoint()
   {
      try
      {
         cst = TimeZoneInfo.FindSystemTimeZoneById("Central Standard Time");
      }   
      catch (TimeZoneNotFoundException)
      {
         if (customTimeZones.ContainsKey("Central Standard Time"))
            HandleTimeZoneException("Central Standard Time");
      }
      catch (InvalidTimeZoneException)
      {
         if (customTimeZones.ContainsKey("Central Standard Time"))
            HandleTimeZoneException("Central Standard Time");
      }               
      if (cst == null)
      {
         Console.WriteLine("Unable to load Central Standard Time zone.");
         return;
      }
      DateTime currentTime = DateTime.Now;
      Console.WriteLine("The current {0} time is {1}.", 
                        TimeZoneInfo.Local.IsDaylightSavingTime(currentTime) ? 
                            TimeZoneInfo.Local.StandardName : 
                            TimeZoneInfo.Local.DaylightName, 
                        currentTime.ToString("f"));
      Console.WriteLine("The current {0} time is {1}.", 
                        cst.IsDaylightSavingTime(currentTime) ? 
                            cst.StandardName : 
                            cst.DaylightName, 
                        TimeZoneInfo.ConvertTime(currentTime, TimeZoneInfo.Local, cst).ToString("f"));
   }

   private void HandleTimeZoneException(string timeZoneName)
   {
      string tzString = customTimeZones[timeZoneName];
      cst = TimeZoneInfo.FromSerializedString(tzString);
   }
}

Archiviazione e ripristino di una stringa serializzata quando necessario

Negli esempi precedenti le informazioni del fuso orario sono state archiviate in una variabile di stringa e ripristinate quando necessario. La stringa che contiene le informazioni del fuso orario serializzato può a sua volta essere archiviata in un supporto di archiviazione, ad esempio un file esterno, un file di risorse incorporato nell'applicazione o il Registro di sistema. Notare che le informazioni sui fusi orari personalizzati devono essere archiviate separatamente dalle chiavi del fuso orario del Registro di sistema.

Se si archivia la stringa del fuso orario serializzato in questo modo, si separa anche la routine di creazione del fuso orario dall'applicazione stessa. Ad esempio, una routine di creazione del fuso orario può eseguire e creare un file di dati che contiene le informazioni sui fusi orari storici utilizzate da un'applicazione. Il file di dati può quindi essere installato con l'applicazione ed essere aperto deserializzando uno o più fusi orari quando richiesto dall'applicazione.

Per un esempio che utilizza una risorsa incorporata per archiviare i dati dei fusi orari serializzati, vedere Procedura: salvare fusi orari in una risorsa incorporata e Procedura: ripristinare i fusi orari da una risorsa incorporata.

Vedere anche

Altre risorse

Ora e fusi orari