방법: 포함 리소스에 표준 시간대 저장

표준 시간대 인식 애플리케이션에는 특정 표준 시간대가 필요한 경우가 많습니다. 그러나 개별 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 파일의 이름과 선택적으로 경로를 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 개체와 남극 팔머 관측소 시간을 나타내는 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
    

참고 항목