Share via


作法:將時區儲存到內嵌資源

時區感知應用程式經常需要有特定時區存在。 不過,因為個別 TimeZoneInfo 物件的可用性取決於儲存在本機系統登錄中的資訊,因此就連自訂可用的時區都可能不存在。 此外,使用 CreateCustomTimeZone 方法具現化之自訂時區的相關資訊,不會與其他時區資訊一起儲存在登錄中。 若要確保這些時區可在需要時使用,您可以藉由序列化它們來儲存它們,稍後再還原序列化它們來加以還原。

一般而言,序列化 TimeZoneInfo 物件與時區感知應用程式分開進行。 根據用來保存序列化 TimeZoneInfo 物件的資料存放區,時區資料可能會序列化為安裝程式或安裝常式的一部分 (例如,當資料儲存在登錄的應用程式機碼中),或作為在編譯最終應用程式之前執行之公用程式常式的一部分 (例如,當序列化的資料儲存在 .NET XML 資源 (.resx) 檔案時)。

除了使用應用程式編譯的資源檔之外,其他數個資料存放區也可用於時區資訊。 其中包括下列各項:

  • 登錄。 請注意,應用程式應該使用其自己的應用程式機碼來儲存自訂時區資料,而不是使用 HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Time Zones 的子機碼。

  • 設定檔。

  • 其他系統檔案。

將時區序列化為 .resx 檔案以儲存時區

  1. 擷取現有的時區,或建立新的時區。

    若要擷取現有的時區,請參閱如何:存取預先定義的 UTC 和當地時區物件如何:具現化 TimeZoneInfo 物件

    若要建立新的時區,請呼叫 CreateCustomTimeZone 方法的其中一個多載。 如需詳細資訊,請參閱 如何:建立不使用調整規則的時區如何:使用有調整規則建立時區

  2. 呼叫 ToSerializedString 方法,以建立包含時區資料的字串。

  3. 藉由提供 .resx 檔案的名稱以及 (選擇性地) .resx 檔案的路徑給 StreamWriter 類別建構函式,以具現化 StreamWriter 物件。

  4. StreamWriter 物件傳遞至 ResXResourceWriter 類別建構函式,以具現化 ResXResourceWriter 物件。

  5. 將時區的序列化字串傳遞至 ResXResourceWriter.AddResource 方法。

  6. 呼叫 ResXResourceWriter.Generate 方法。

  7. 呼叫 ResXResourceWriter.Close 方法。

  8. 呼叫 StreamWriter 物件的 Close 方法以關閉物件。

  9. 將產生的 .resx 檔案新增至應用程式的 Visual Studio 專案。

  10. 使用 Visual Studio 中的 [屬性] 視窗,確定 .resx 檔案的 [建置動作] 屬性已設定為 [內嵌資源]

範例

下列範例會將代表中央標準時間的 TimeZoneInfo 物件序列化,並將代表南極洲帕麥站時間的 TimeZoneInfo 物件序列化為名為 SerializedTimeZones.resx 的 .NET XML 資源檔。 中央標準時間通常會定義於登錄中;南極洲帕麥站是自訂時區。

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

這個範例會序列化 TimeZoneInfo 物件,以便它們在編譯時期於資源檔中可供使用。

由於 ResXResourceWriter.Generate 方法會將完整的標頭資訊新增至 .NET XML 資源檔,因此無法用來將資源新增至現有的檔案。 此範例處理此問題的方式是,檢查是否有 SerializedTimeZones.resx 檔案,如果存在,則會將兩個序列化時區除外的其所有資源儲存到泛型 Dictionary<TKey,TValue> 物件。 接著會刪除現有的檔案,並將現有的資源新增至新的 SerializedTimeZones.resx 檔案。 序列化的時區資料也會新增至此檔案。

資源的索引鍵 (或名稱) 欄位不應包含內嵌空格。 系統會呼叫 Replace(String, String) 方法來移除時區識別碼中的所有內嵌空間,再將其指派給資源檔。

編譯程式碼

這個範例需要:

  • 將 System.Windows.Forms.dll 和 System.Core.dll 的參考新增至專案。

  • 匯入下列命名空間:

    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
    

另請參閱