方法 : 埋め込みリソースにタイム ゾーンを保存する

タイム ゾーンに対応したアプリケーションでは、多くの場合、特定のタイム ゾーンが存在する必要があります。 しかし、個別の TimeZoneInfo オブジェクトを使用できるかどうかはローカル システムのレジストリに格納されている情報に依存するので、通常は使用できるタイム ゾーンであっても存在しない場合があります。 さらに、CreateCustomTimeZone メソッドを使用することでインスタンス化されるカスタム タイム ゾーンについての情報は、他のタイム ゾーン情報とは異なりレジストリに格納されません。 このようなタイム ゾーンを必要なときに確実に使用できるようにするには、タイム ゾーンをシリアル化して保存し、必要になったら逆シリアル化して復元します。

通常、TimeZoneInfo オブジェクトのシリアル化は、タイム ゾーンに対応するアプリケーションとは関係なく行われます。 シリアル化された TimeZoneInfo オブジェクトの保持に使用するデータ ストアによっては、セットアップ ルーチンまたはインストール ルーチンの一部として (たとえば、データがレジストリのアプリケーション キーに格納されるとき)、または最終的なアプリケーションがコンパイルされる前に実行するユーティリティ ルーチンの一部として (たとえば、シリアル化されたデータが .NET XML リソース (.resx) ファイルに格納されるとき)、タイム ゾーンのデータをシリアル化できます。

アプリケーションと共にコンパイルされるリソース ファイル以外に、複数のデータ ストアをタイム ゾーン情報に使用できます。 次に例を示します。

  • レジストリ。 アプリケーションでは、HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Time Zones というサブキーを使用するのではなく、アプリケーション自体のキーのサブキーを使用してカスタム タイム ゾーン データを格納する必要があります。

  • 構成ファイル。

  • その他のシステム ファイル。

.resx ファイルにシリアル化してタイム ゾーンを保存するには

  1. 既存のタイム ゾーンを取得するか、新しいタイム ゾーンを作成します。

    既存のタイム ゾーンを取得する方法については、「方法 : 定義済みの UTC オブジェクトおよびローカル タイム ゾーン オブジェクトにアクセスする」および「方法 : TimeZoneInfo オブジェクトをインスタンス化する」を参照してください。

    新しいタイム ゾーンを作成するには、CreateCustomTimeZone メソッドのオーバーロードの 1 つを呼び出します。 詳細については、「方法 : 調整規則のないタイム ゾーンを作成する」および「方法 : 調整規則のあるタイム ゾーンを作成する」を参照してください。

  2. ToSerializedString メソッドを呼び出して、タイム ゾーンのデータを含む文字列を作成します。

  3. .resx ファイルの名前、および必要に応じてファイルへのパスを StreamWriter クラスのコンストラクターに渡して、StreamWriter オブジェクトをインスタンス化します。

  4. StreamWriter オブジェクトを ResXResourceWriter クラスのコンストラクターに渡して、ResXResourceWriter オブジェクトをインスタンス化します。

  5. タイム ゾーンのシリアル化された文字列を、ResXResourceWriter.AddResource メソッドに渡します。

  6. ResXResourceWriter.Generate メソッドを呼び出します。

  7. ResXResourceWriter.Close メソッドを呼び出します。

  8. Close メソッドを呼び出して、StreamWriter オブジェクトを閉じます。

  9. 生成された .resx ファイルを、アプリケーションの Visual Studio プロジェクトに追加します。

  10. Visual Studio の [プロパティ] ウィンドウを使用して、.resx ファイルの [ビルド アクション] プロパティが [埋め込まれたリソース] に設定されていることを確認します。

使用例

次の例では、中部標準時を表す TimeZoneInfo オブジェクトと、Palmer Station, Antarctica 時刻を表す TimeZoneInfo オブジェクトを、SerializedTimeZones.resx という名前の .NET XML リソース ファイルにシリアル化します。 普通、中部標準時はレジストリで定義されています。Palmer Station, Antarctica はカスタム タイム ゾーンです。

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 ファイルを検査することでこのことに対処しています。ファイルが存在する場合は、シリアル化した 2 つのタイム ゾーン以外のすべてのリソースを、汎用の 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;
    

参照

処理手順

方法 : 埋め込みリソースからタイム ゾーンを復元する

概念

タイム ゾーンの概要

その他の技術情報

日付、時刻、およびタイム ゾーン