Procedura: Salvare fusi orari in una risorsa incorporata
Un'applicazione compatibile con il fuso orario richiede spesso la presenza di un particolare fuso orario. Tuttavia, poiché la disponibilità di singoli oggetti TimeZoneInfo dipende dalle informazioni archiviate nel Registro di sistema locale, anche i fusi orari disponibili personalizzati potrebbero essere assenti. Inoltre, le informazioni sui fusi orari personalizzati create tramite il metodo CreateCustomTimeZone non vengono archiviate con altre informazioni sul fuso orario nel Registro di sistema. Per assicurarsi che questi fusi orari siano disponibili quando necessario, è possibile salvarli serializzandoli e successivamente ripristinandoli con la deserializzazione.
In genere, la serializzazione di un oggetto TimeZoneInfo si verifica in modo indipendente dall'applicazione che riconosce il fuso orario. A seconda dell'archivio dati usato per contenere oggetti TimeZoneInfo serializzati, i dati del fuso orario possono essere serializzati come parte di una routine di installazione o configurazione (ad esempio quando i dati vengono archiviati in una chiave dell'applicazione del Registro di sistema) o come parte di una routine di utilità eseguita prima della compilazione dell'applicazione finale (ad esempio quando i dati serializzati vengono archiviati in un file di risorse XML .NET con estensione resx).
Oltre a un file di risorse compilato con l'applicazione, è possibile usare diversi altri archivi dati per le informazioni sul fuso orario. Di seguito sono elencate le quattro opzioni disponibili.
Il registro. Si noti che un'applicazione deve usare le sottochiavi della propria chiave dell'applicazione per archiviare dati di fuso orario personalizzati anziché usare le sottochiavi di HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Time Zones.
File di configurazione.
Altri file di sistema.
Per salvare un fuso orario serializzandolo in un file resx
Recuperare un fuso orario esistente o creare un nuovo fuso orario.
Per recuperare un fuso orario esistente, vedere Procedura: Accedere agli oggetti fuso orario UTC e locali predefiniti e Procedura: Creare un'istanza di un oggetto TimeZoneInfo.
Per creare un nuovo fuso orario, chiamare uno degli overload del metodo CreateCustomTimeZone. Per altre informazioni, vedere Procedura: Creare fusi orari senza regole di rettifica e Procedura: Creare fusi orari con regole di rettifica.
Chiamare il metodo ToSerializedString per creare una stringa contenente i dati del fuso orario.
Creare un'istanza di un oggetto StreamWriter specificando il nome e, facoltativamente, il percorso del file resx al costruttore della classe StreamWriter.
Creare un'istanza di un oggetto ResXResourceWriter passando l'oggetto StreamWriter al costruttore della classe ResXResourceWriter.
Passare la stringa serializzata del fuso orario al metodo ResXResourceWriter.AddResource.
Chiamare il metodo ResXResourceWriter.Generate .
Chiamare il metodo ResXResourceWriter.Close .
Chiudere l'oggetto StreamWriter chiamando il relativo metodo Close.
Aggiungere il file resx generato al progetto di Visual Studio dell'applicazione.
Usando la finestra Proprietà in Visual Studio, assicurarsi che la proprietà Azione di compilazione del file resx sia impostata su Risorsa incorporata.
Esempio
Nell'esempio seguente viene serializzato un oggetto TimeZoneInfo che rappresenta l'ora solare centrale e un oggetto TimeZoneInfo che rappresenta l'ora di Palmer Station, Antartide in un file di risorse XML .NET denominato SerializedTimeZones.resx. L'ora solare centrale viene in genere definita nel Registro di sistema; Palmer Station, Antartide è un fuso orario personalizzato.
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
Questo esempio serializza gli oggetti TimeZoneInfo in modo che siano disponibili in un file di risorse in fase di compilazione.
Poiché il metodo ResXResourceWriter.Generate aggiunge informazioni di intestazione complete a un file di risorse XML .NET, non può essere usato per aggiungere risorse a un file esistente. Questo esempio viene gestito controllando il file SerializedTimeZones.resx e, se esistente, archiviando tutte le relative risorse diverse dai due fusi orari serializzati in un oggetto Dictionary<TKey,TValue> generico. Il file esistente viene quindi eliminato e le risorse esistenti vengono aggiunte a un nuovo file SerializedTimeZones.resx. Anche i dati del fuso orario serializzati vengono aggiunti a questo file.
I campi chiave (o Nome) delle risorse non devono contenere spazi incorporati. Il metodo Replace(String, String) viene chiamato per rimuovere tutti gli spazi incorporati negli identificatori del fuso orario prima che vengano assegnati al file di risorse.
Compilazione del codice
L'esempio presenta i requisiti seguenti:
Che un riferimento a System.Windows.Forms.dll e System.Core.dll verrà aggiunto al progetto.
Che verranno importati gli spazi dei nomi seguenti:
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