Bagikan melalui


Menyimpan dan memulihkan zona waktu

Kelas TimeZoneInfo bergantung pada registri untuk mengambil data zona waktu yang telah ditentukan sebelumnya. Namun, registri adalah struktur dinamis. Selain itu, informasi zona waktu yang dikandung registri digunakan oleh sistem operasi terutama untuk menangani penyesuaian waktu dan konversi untuk tahun ini. Ini memiliki dua implikasi utama untuk aplikasi yang mengandalkan data zona waktu yang akurat:

  • Zona waktu yang diperlukan oleh aplikasi tidak dapat ditentukan dalam registri, atau telah diganti namanya atau dihapus dari registri.

  • Zona waktu yang ditentukan dalam registri tidak dapat memiliki informasi tentang aturan penyesuaian tertentu yang diperlukan untuk konversi zona waktu historis.

Kelas TimeZoneInfo membahas batasan ini melalui dukungannya untuk serialisasi (menyimpan) dan deserialisasi (memulihkan) data zona waktu.

Serialisasi dan deserialisasi zona waktu

Menyimpan dan memulihkan zona waktu dengan menserialisasikan dan mendeserialisasi data zona waktu hanya melibatkan dua panggilan metode:

  • Anda dapat menserialisasikan TimeZoneInfo objek dengan memanggil metode objek tersebut ToSerializedString. Metode ini tidak mengambil parameter dan mengembalikan string yang berisi informasi zona waktu.

  • Anda dapat mendeserialisasi TimeZoneInfo objek dari string berseri dengan meneruskan string tersebut static ke metode (Shared dalam Visual BasicTimeZoneInfo.FromSerializedString).

Skenario serialisasi dan deserialisasi

Kemampuan untuk menyimpan (atau menserialisasikan) TimeZoneInfo objek ke string dan memulihkan (atau mendeserialisasi) untuk digunakan nanti meningkatkan utilitas dan fleksibilitas TimeZoneInfo kelas. Bagian ini memeriksa beberapa situasi di mana serialisasi dan deserialisasi paling berguna.

Menserialisasikan dan mendeserialisasi data zona waktu dalam aplikasi

Zona waktu berseri dapat dipulihkan dari string saat diperlukan. Aplikasi dapat melakukan ini jika zona waktu yang diambil dari registri tidak dapat mengonversi tanggal dan waktu dengan benar dalam rentang tanggal tertentu. Misalnya, data zona waktu di registri XP Windows mendukung aturan penyesuaian tunggal, sementara zona waktu yang ditentukan dalam registri Windows Vista biasanya memberikan informasi tentang dua aturan penyesuaian. Ini berarti bahwa konversi waktu historis bisa tidak akurat. Serialisasi dan deserialisasi data zona waktu dapat menangani batasan ini.

Dalam contoh berikut, kelas kustom TimeZoneInfo yang tidak memiliki aturan penyesuaian didefinisikan untuk mewakili zona Waktu Standar Timur AS dari 1883 hingga 1917, sebelum pengenalan waktu musim panas di Amerika Serikat. Zona waktu kustom diserialisasikan dalam variabel yang memiliki cakupan global. Metode konversi zona waktu, ConvertUtcTime, dilewatkan waktu Waktu Universal Terkoordinasi untuk dikonversi. Jika tanggal dan waktu terjadi pada tahun 1917 atau lebih lama, zona Waktu Standar Timur kustom dipulihkan dari string berseri dan menggantikan zona waktu yang diambil dari registri.

using System;

public class TimeZoneSerialization
{
   static string serializedEst;

   public static void Main()
   {
      // Retrieve Eastern Standard Time zone from registry
      try
      {
         TimeZoneSerialization tzs = new TimeZoneSerialization();
         TimeZoneInfo est = TimeZoneInfo.FindSystemTimeZoneById("Eastern Standard Time");
         // Create custom Eastern Time Zone for historical (pre-1918) conversions
         CreateTimeZone();
         // Call conversion function with one current and one pre-1918 date and time
         Console.WriteLine(ConvertUtcTime(DateTime.UtcNow, est));
         Console.WriteLine(ConvertUtcTime(new DateTime(1900, 11, 15, 9, 32, 00, DateTimeKind.Utc), est));
      }
      catch (TimeZoneNotFoundException)
      {
         Console.WriteLine("The Eastern Standard Time zone is not in the registry.");
      }
      catch (InvalidTimeZoneException)
      {
         Console.WriteLine("Data on the Eastern Standard Time Zone in the registry is corrupted.");
      }
   }

   private static void CreateTimeZone()
   {
      // Create a simple Eastern Standard time zone
      // without adjustment rules for 1883-1918
      TimeZoneInfo earlyEstZone = TimeZoneInfo.CreateCustomTimeZone("Eastern Standard Time",
                                      new TimeSpan(-5, 0, 0),
                                      " (GMT-05:00) Eastern Time (United States)",
                                      "Eastern Standard Time");
      serializedEst = earlyEstZone.ToSerializedString();
   }

   private static DateTime ConvertUtcTime(DateTime utcDate, TimeZoneInfo tz)
   {
      // Use time zone object from registry
      if (utcDate.Year > 1917)
      {
         return TimeZoneInfo.ConvertTimeFromUtc(utcDate, tz);
      }
      // Handle dates before introduction of DST
      else
      {
         // Restore serialized time zone object
         tz = TimeZoneInfo.FromSerializedString(serializedEst);
         return TimeZoneInfo.ConvertTimeFromUtc(utcDate, tz);
      }
   }
}
Module TimeZoneSerialization
    Dim serializedEst As String

    Public Sub Main()
        ' Retrieve Eastern Standard Time zone from registry
        Try
            Dim est As TimeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById("Eastern Standard Time")
            ' Create custom Eastern Time Zone for historical (pre-1918) conversions
            CreateTimeZone()
            ' Call conversion function with one current and one pre-1918 date and time
            Console.WriteLine(ConvertUtcTime(Date.UtcNow, est))
            Console.WriteLine(ConvertUtcTime(New Date(1900, 11, 15, 9, 32, 00, DateTimeKind.Utc), est))
        Catch e As TimeZoneNotFoundException
            Console.WriteLine("The Eastern Standard Time zone is not in the registry.")
        Catch e As InvalidTimeZoneException
            Console.WriteLine("Data on the Eastern Standard Time Zone in the registry is corrupted.")
        End Try
    End Sub

    Private Sub CreateTimeZone()
        ' Create a simple Eastern Standard time zone 
        ' without adjustment rules for 1883-1918
        Dim earlyEstZone As TimeZoneInfo = TimeZoneInfo.CreateCustomTimeZone("Eastern Standard Time", _
                                        New TimeSpan(-5, 0, 0), _
                                        " (GMT-05:00) Eastern Time (United States)", _
                                        "Eastern Standard Time")
        serializedEst = earlyEstZone.ToSerializedString()
    End Sub

    Private Function ConvertUtcTime(utcDate As Date, tz As TimeZoneInfo) As Date
        ' Use time zone object from registry 
        If Year(utcDate) > 1917 Then
            Return TimeZoneInfo.ConvertTimeFromUtc(utcDate, tz)
            ' Handle dates before introduction of DST
        Else
            ' Restore serialized time zone object
            tz = TimeZoneInfo.FromSerializedString(serializedEst)
            Return TimeZoneInfo.ConvertTimeFromUtc(utcDate, tz)
        End If
    End Function
End Module

Menangani pengecualian zona waktu

Karena registri adalah struktur dinamis, kontennya tunduk pada modifikasi yang tidak disengaja atau disengaja. Ini berarti bahwa zona waktu yang harus didefinisikan dalam registri dan yang diperlukan agar aplikasi berhasil dijalankan mungkin tidak ada. Tanpa dukungan untuk serialisasi zona waktu dan deserialisasi, Anda memiliki sedikit pilihan tetapi untuk menangani yang dihasilkan TimeZoneNotFoundException dengan mengakhiri aplikasi. Namun, dengan menggunakan serialisasi dan deserialisasi zona waktu, Anda dapat menangani hal yang tidak terduga TimeZoneNotFoundException dengan memulihkan zona waktu yang diperlukan dari string yang diserialisasikan, dan aplikasi akan terus berjalan.

Contoh berikut membuat dan menserialisasikan zona Waktu Standar Pusat kustom. Kemudian mencoba mengambil zona Waktu Standar Pusat dari registri. Jika operasi pengambilan melempar TimeZoneNotFoundException atau InvalidTimeZoneException, handler pengecualian mendeserialisasi zona waktu.

using System;
using System.Collections.Generic;

public class TimeZoneApplication
{
   // Define collection of custom time zones
   private Dictionary<string, string> customTimeZones = new Dictionary<string, string>();
   private TimeZoneInfo cst;

   public TimeZoneApplication()
   {
      // Create custom Central Standard Time
      //
      // Declare necessary TimeZoneInfo.AdjustmentRule objects for time zone
      TimeZoneInfo customTimeZone;
      TimeSpan delta = new TimeSpan(1, 0, 0);
      TimeZoneInfo.AdjustmentRule adjustment;
      List<TimeZoneInfo.AdjustmentRule> adjustmentList = new List<TimeZoneInfo.AdjustmentRule>();
      // Declare transition time variables to hold transition time information
      TimeZoneInfo.TransitionTime transitionRuleStart, transitionRuleEnd;

      // Define end rule (for 1976-2006)
      transitionRuleEnd = TimeZoneInfo.TransitionTime.CreateFloatingDateRule(new DateTime(1, 1, 1, 2, 0, 0), 10, 5, DayOfWeek.Sunday);
      // Define rule (1976-1986)
      transitionRuleStart = TimeZoneInfo.TransitionTime.CreateFloatingDateRule(new DateTime(1, 1, 1, 2, 0, 0), 04, 05, DayOfWeek.Sunday);
      adjustment = TimeZoneInfo.AdjustmentRule.CreateAdjustmentRule(new DateTime(1976, 1, 1), new DateTime(1986, 12, 31), delta, transitionRuleStart, transitionRuleEnd);
      adjustmentList.Add(adjustment);
      // Define rule (1987-2006)
      transitionRuleStart = TimeZoneInfo.TransitionTime.CreateFloatingDateRule(new DateTime(1, 1, 1, 2, 0, 0), 04, 01, DayOfWeek.Sunday);
      adjustment = TimeZoneInfo.AdjustmentRule.CreateAdjustmentRule(new DateTime(1987, 1, 1), new DateTime(2006, 12, 31), delta, transitionRuleStart, transitionRuleEnd);
      adjustmentList.Add(adjustment);
      // Define rule (2007- )
      transitionRuleStart = TimeZoneInfo.TransitionTime.CreateFloatingDateRule(new DateTime(1, 1, 1, 2, 0, 0), 03, 02, DayOfWeek.Sunday);
      transitionRuleEnd = TimeZoneInfo.TransitionTime.CreateFloatingDateRule(new DateTime(1, 1, 1, 2, 0, 0), 11, 01, DayOfWeek.Sunday);
      adjustment = TimeZoneInfo.AdjustmentRule.CreateAdjustmentRule(new DateTime(2007, 01, 01), DateTime.MaxValue.Date, delta, transitionRuleStart, transitionRuleEnd);
      adjustmentList.Add(adjustment);

      // Create custom U.S. Central Standard Time zone
      customTimeZone = TimeZoneInfo.CreateCustomTimeZone("Central Standard Time",
                      new TimeSpan(-6, 0, 0),
                      "(GMT-06:00) Central Time (US Only)", "Central Standard Time",
                      "Central Daylight Time", adjustmentList.ToArray());
      // Add time zone to collection
      customTimeZones.Add(customTimeZone.Id, customTimeZone.ToSerializedString());

      // Create any other required time zones
   }

   public static void Main()
   {
      TimeZoneApplication tza = new TimeZoneApplication();
      tza.AppEntryPoint();
   }

   private void AppEntryPoint()
   {
      try
      {
         cst = TimeZoneInfo.FindSystemTimeZoneById("Central Standard Time");
      }
      catch (TimeZoneNotFoundException)
      {
         if (customTimeZones.ContainsKey("Central Standard Time"))
            HandleTimeZoneException("Central Standard Time");
      }
      catch (InvalidTimeZoneException)
      {
         if (customTimeZones.ContainsKey("Central Standard Time"))
            HandleTimeZoneException("Central Standard Time");
      }
      if (cst == null)
      {
         Console.WriteLine("Unable to load Central Standard Time zone.");
         return;
      }
      DateTime currentTime = DateTime.Now;
      Console.WriteLine("The current {0} time is {1}.",
                        TimeZoneInfo.Local.IsDaylightSavingTime(currentTime) ?
                            TimeZoneInfo.Local.StandardName :
                            TimeZoneInfo.Local.DaylightName,
                        currentTime.ToString("f"));
      Console.WriteLine("The current {0} time is {1}.",
                        cst.IsDaylightSavingTime(currentTime) ?
                            cst.StandardName :
                            cst.DaylightName,
                        TimeZoneInfo.ConvertTime(currentTime, TimeZoneInfo.Local, cst).ToString("f"));
   }

   private void HandleTimeZoneException(string timeZoneName)
   {
      string tzString = customTimeZones[timeZoneName];
      cst = TimeZoneInfo.FromSerializedString(tzString);
   }
}
Imports System.Collections.Generic

Public Class TimeZoneApplication
    ' Define collection of custom time zones
    Private customTimeZones As New Dictionary(Of String, String)
    Private cst As TimeZoneInfo

    Public Sub New()
        ' Define custom Central Standard Time
        '
        ' Declare necessary TimeZoneInfo.AdjustmentRule objects for time zone
        Dim customTimeZone As TimeZoneInfo
        Dim delta As New TimeSpan(1, 0, 0)
        Dim adjustment As TimeZoneInfo.AdjustmentRule
        Dim adjustmentList As New List(Of TimeZoneInfo.AdjustmentRule)
        ' Declare transition time variables to hold transition time information
        Dim transitionRuleStart, transitionRuleEnd As TimeZoneInfo.TransitionTime

        ' Define end rule (for 1976-2006)
        transitionRuleEnd = TimeZoneInfo.TransitionTime.CreateFloatingDateRule(#02:00:00AM#, 10, 5, DayOfWeek.Sunday)
        ' Define rule (1976-1986)
        transitionRuleStart = TimeZoneInfo.TransitionTime.CreateFloatingDateRule(#2:00:00AM#, 04, 05, DayOfWeek.Sunday)
        adjustment = TimeZoneInfo.AdjustmentRule.CreateAdjustmentRule(#01/01/1976#, #12/31/1986#, delta, transitionRuleStart, transitionRuleEnd)
        adjustmentList.Add(adjustment)
        ' Define rule (1987-2006)  
        transitionRuleStart = TimeZoneInfo.TransitionTime.CreateFloatingDateRule(#2:00:00AM#, 04, 01, DayOfWeek.Sunday)
        adjustment = TimeZoneInfo.AdjustmentRule.CreateAdjustmentRule(#01/01/1987#, #12/31/2006#, delta, transitionRuleStart, transitionRuleEnd)
        adjustmentList.Add(adjustment)
        ' Define rule (2007- )  
        transitionRuleStart = TimeZoneInfo.TransitionTime.CreateFloatingDateRule(#2:00:00AM#, 03, 02, DayOfWeek.Sunday)
        transitionRuleEnd = TimeZoneInfo.TransitionTime.CreateFloatingDateRule(#2:00:00AM#, 11, 01, DayOfWeek.Sunday)
        adjustment = TimeZoneInfo.AdjustmentRule.CreateAdjustmentRule(#01/01/2007#, Date.MaxValue.Date, delta, transitionRuleStart, transitionRuleEnd)
        adjustmentList.Add(adjustment)
        ' Create custom time zone
        customTimeZone = TimeZoneInfo.CreateCustomTimeZone("Central Standard Time", _
                        New TimeSpan(-6, 0, 0), _
                        "(GMT-06:00) Central Time (US Only)", "Central Standard Time", _
                        "Central Daylight Time", adjustmentList.ToArray())
        ' Add time zone to collection
        customTimeZones.Add(customTimeZone.Id, customTimeZone.ToSerializedString())

        ' Create any other required time zones     
    End Sub

    Public Shared Sub Main()
        Dim tza As New TimeZoneApplication()
        tza.AppEntryPoint()
    End Sub

    Private Sub AppEntryPoint()
        Try
            cst = TimeZoneInfo.FindSystemTimeZoneById("Central Standard Time")
        Catch e As TimeZoneNotFoundException
            If customTimeZones.ContainsKey("Central Standard Time")
                HandleTimeZoneException("Central Standard Time")
            End If
        Catch e As InvalidTimeZoneException
            If customTimeZones.ContainsKey("Central Standard Time")
                HandleTimeZoneException("Central Standard Time")
            End If
        End Try
        If cst Is Nothing Then
            Console.WriteLine("Unable to load Central Standard Time zone.")
            Return
        End If
        Dim currentTime As Date = Date.Now
        Console.WriteLine("The current {0} time is {1}.", _
                          IIf(TimeZoneInfo.Local.IsDaylightSavingTime(currentTime), _
                              TimeZoneInfo.Local.StandardName, _
                              TimeZoneInfo.Local.DaylightName), _
                          currentTime.ToString("f"))
        Console.WriteLine("The current {0} time is {1}.", _
                          IIf(cst.IsDaylightSavingTime(currentTime), _
                              cst.StandardName, _
                              cst.DaylightName), _
                          TimeZoneInfo.ConvertTime(currentTime, TimeZoneInfo.Local, cst).ToString("f"))
    End Sub

    Private Sub HandleTimeZoneException(timeZoneName As String)
        Dim tzString As String = customTimeZones.Item(timeZoneName)
        cst = TimeZoneInfo.FromSerializedString(tzString)
    End Sub
End Class

Menyimpan string berseri dan memulihkannya saat diperlukan

Contoh sebelumnya telah menyimpan informasi zona waktu ke variabel string dan memulihkannya saat diperlukan. Namun, string yang berisi informasi zona waktu berseri dapat disimpan di beberapa media penyimpanan, seperti file eksternal, file sumber daya yang disematkan dalam aplikasi, atau registri. (Perhatikan bahwa informasi tentang zona waktu kustom harus disimpan selain dari kunci zona waktu sistem di registri.)

Menyimpan string zona waktu berseri dengan cara ini juga memisahkan rutinitas pembuatan zona waktu dari aplikasi itu sendiri. Misalnya, rutinitas pembuatan zona waktu dapat menjalankan dan membuat file data yang berisi informasi zona waktu historis yang dapat digunakan aplikasi. File data kemudian dapat diinstal dengan aplikasi, dan dapat dibuka dan satu atau beberapa zona waktunya dapat dideserialisasi ketika aplikasi memerlukannya.

Untuk contoh yang menggunakan sumber daya yang disematkan untuk menyimpan data zona waktu serial, lihat Cara: Menyimpan zona waktu ke sumber daya yang disematkan dan Cara: Memulihkan zona waktu dari sumber daya yang disematkan.

Lihat juga