Практическое руководство. Сохранение часовых поясов во внедренном ресурсе
Часто приложению, работающему со временем, требуется наличие определенного часового пояса. Однако поскольку доступность отдельных объектов TimeZoneInfo зависит от сведений, хранящихся в локальном реестре пользователя, даже настраиваемые доступные часовые пояса могут отсутствовать. Кроме того, сведения о пользовательских часовых поясах, созданных с помощью метода CreateCustomTimeZone, не хранятся с другими сведениями о часовом поясе в реестре. Чтобы гарантировать, что эти часовые пояса будут доступны, когда потребуется, их можно сериализовать и сохранить, а позже десериализовать и восстановить.
Обычно сериализация объекта TimeZoneInfo происходит отдельно от приложения, соответствующего часовому поясу. В зависимости от хранилища данных, используемого для хранения сериализованных объектов TimeZoneInfo, данные о часовых поясах можно сериализовывать в процессе установки (например, при сохранении данных в ключе реестра), или как часть служебной процедуры, запускаемой перед окончательной компиляцией приложения (например, когда сериализованные данные хранятся в файле ресурсов (.resX) .NET XML).
В дополнение к файлу ресурсов, который компилируется с приложением, для хранения сведений о часовом поясе могут использоваться некоторые другие хранилища. В их числе:
Реестр. Обратите внимание, что для хранения пользовательских данных о часовом поясе приложение должно использовать вложенные разделы своего собственного реестра приложения вместо использования подразделов HKEY_LOCAL_MACHINE\Software\Microsoft\Windows NT\CurrentVersion\Time Zones.
Файлы конфигурации.
Другие системные файлы.
Для сохранения часового пояса путем сериализации его в файле .resx
Извлеките существующий часовой пояс или создайте новый часовой пояс.
Сведения об извлечении текущего часового пояса см. в разделах Практическое руководство. Доступ к предварительно определенным объектам UTC и объектам местных часовых поясов и Практическое руководство. Создание экземпляра объекта TimeZoneInfo.
Чтобы создать новый часовой пояс, вызовите один из вариантов перегруженного метода CreateCustomTimeZone. Дополнительные сведения см. в разделах Практическое руководство. Создание часовых поясов без правил коррекции и Практическое руководство. Создание часовых поясов с правилами коррекции.
Вызовите метод ToSerializedString для создания строки, содержащей данные часового пояса.
Создайте объект StreamWriter, передав имя и при необходимости путь к файлу .resx в конструктор класса StreamWriter.
Создайте объект ResXResourceWriter путем передачи объекта StreamWriter в конструктор класса ResXResourceWriter.
Передайте сериализованную строку часового пояса в метод ResXResourceWriter.AddResource.
Вызовите метод ResXResourceWriter.Generate.
Вызовите метод ResXResourceWriter.Close.
Закройте объект StreamWriter путем вызова его метода Close.
Добавьте созданный файл .resx в проект приложения Visual Studio.
С помощью окна Свойства в Visual Studio, убедитесь, что свойство Действия при построении этого файла .resx задано как Внедренный ресурс.
Пример
В следующем примере объект TimeZoneInfo, представляющий центральное стандартное время и объект TimeZoneInfo, представляющий антарктическое время, сериализуются в файле .NET XML ресурсов под именем SerializedTimeZones.resx. Центральное стандартное время обычно определено в реестре; антарктическое время является пользовательским часовым поясом.
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();
}
Этот пример сериализует объекты TimeZoneInfo таким образом, что они становятся доступными в файле ресурсов во время компиляции.
Поскольку метод ResXResourceWriter.Generate добавляет полные сведения заголовка в файл ресурсов .NET XML, то он не может использоваться для добавления ресурсов в существующий файл. Этот пример проводит обработку путем проверки файла SerializedTimeZones.resx и, если он существует, сохранения всех его ресурсов, отличных от этих двух сериализованных часовых поясов в универсальный объект Dictionary<TKey, TValue>. Затем существующий файл удаляется, и существующие ресурсы добавляются в новый файл SerializedTimeZones.resx. Сериализованные данные часового пояса также добавляются в этот файл.
Ключ (или Имя) полей ресурсов не должен содержать пробелы. Метод Replace(String, String) вызывается для удаления всех пробелов в идентификаторах часовых поясов, прежде чем они помещаются в файл ресурсов.
Компиляция кода
Для этого примера требуется:
Чтобы ссылки на System.Windows.Forms.dll и System.Core.dll были добавлены в проект.
Чтобы был осуществлен импорт следующих пространств имен:
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;
См. также
Задачи
Практическое руководство. Восстановление часовых поясов из внедренного ресурса
Основные понятия
Общие сведения о часовых поясах