共用方式為


在 DateTime、DateTimeOffset 和 TimeZoneInfo 之間選擇

使用日期和時間資訊的 .NET Framework 應用程式有很多種,而且可以利用幾種不同方式使用該資訊。 日期和時間資訊的常見使用方式包括下列一項或多項:

  • 只反映日期,因此時間資訊不重要。

  • 只反映時間,因此日期資訊不重要。

  • 反映絕對日期和時間,該日期和時間不屬於特定時間和地點 (例如,跨國連鎖的大多數商店都在星期一至五早上 9:00 開門營業)。

  • 從 .NET Framework 以外的來源擷取日期和時間資訊,在這些來源中,日期和時間資訊通常是以簡單的資料型別儲存。

  • 以唯一且明確的方式識別單一時間點。 有些應用程式只需要主機系統上有明確的日期和時間,有些則需要所有系統都有明確的日期和時間 (也就是說,在某一系統上序列化的日期,可在全球任何一處的另一個系統上有意義地還原序列化和使用)。

  • 保留多個相關時間 (例如要求者的本地時間以及伺服器收到 Web 要求的時間)。

  • 執行日期和時間運算,可能是對唯一且明確識別單一時間點的結果執行。

.NET Framework 包含 DateTimeDateTimeOffsetTimeZoneInfo 型別,這些型別都可用來建置使用日期和時間的應用程式。

注意事項注意事項

本主題不討論第四個型別 TimeZone,因為它的功能幾乎已完全整合到 TimeZoneInfo 類別。開發人員應盡可能使用 TimeZoneInfo 類別,而不要使用 TimeZone 類別。

DateTime 結構

定義特定日期和時間的 DateTime 值。 從 .NET Framework 2.0 版開始,此結構加入了 Kind 屬性,此屬性可對日期和時間所屬的時區提供有限的資訊。 Kind 屬性傳回的 DateTimeKind 值,會指出 DateTime 值所表示的是本地時間 (DateTimeKind.Local)、國際標準時間 (UTC) (DateTimeKind.Utc) 或未指定的時間 (DateTimeKind.Unspecified)。

DateTime 結構適用於執行下列作業的應用程式:

  • 只使用日期。

  • 只使用時間。

  • 使用絕對日期和時間。

  • 從 .NET Framework 以外的來源 (例如 SQL 資料庫) 擷取日期和時間資訊。 一般來說,這些來源會使用與 DateTime 結構相容的簡單格式儲存日期和時間資訊。

  • 執行日期和時間運算,但通常與運算結果相關。 例如,在將六個月加到特定日期和時間的加法運算中,結果是否調整為日光節約時間通常並不重要。

除非特定 DateTime 值表示的是 UTC,否則該日期和時間值通常是模稜兩可或可攜性有限。 例如,如果 DateTime 值表示本地時間,則在該本地時區內具可攜性 (也就是說,如果此值在同時區的另一個系統上還原序列化,則仍可明確識別某個單一時間點)。 在本地時區以外,該 DateTime 值就可能有多種解讀。 如果值的 Kind 屬性為 DateTimeKind.Unspecified,那麼可攜性就更低:現在它在同時區內會是模稜兩可的,甚至可能在最初序列化的同一個系統上也是如此。 只有在 DateTime 值表示 UTC 的情況下,該值才能在明確識別單一時間點,不論使用它的系統或時區為何。

重要事項重要事項

儲存或共用 DateTime 資料時,應該使用 UTC,並將 DateTime 值的 Kind 屬性設為 DateTimeKind.Utc

DateTimeOffset 結構

DateTimeOffset 結構表示日期和時間值,以及指出該值與 UTC 時差的位移。 因此,此值永遠會以明確方式識別單一時間點。

雖然 DateTimeOffset 型別包含 DateTime 型別的大部分功能,但它並不是要用來在應用程式開發取代 DateTime 型別。 反之,它適合用於執行下列作業的應用程式:

  • 以唯一且明確的方式識別單一時間點。 DateTimeOffset 型別可用來明確定義「現在」的意義,記錄交易時間、記錄系統或應用程式事件的時間,以及記錄檔案建立和修改的時間。

  • 執行一般日期和時間運算。

  • 保留多個相關時間,但前提是這些時間儲存成兩個不同的值,或是結構的兩個成員。

注意事項注意事項

以上使用 DateTimeOffset 值的情形要比使用 DateTime 值常見許多。因此,在進行應用程式開發時,請考慮使用 DateTimeOffset 做為預設日期和時間型別。

DateTimeOffset 值不屬於特定的時區,但可能來自各個不同的時區。 為說明此點,下列範例列出了數個 DateTimeOffset 值 (包括本地太平洋標準時間) 可能屬於的時區。

Imports System.Collections.ObjectModel

Module TimeOffsets
   Public Sub Main()
      Dim thisTime As DateTimeOffset 

      thisTime = New DateTimeOffset(#06/10/2007#, New TimeSpan(-7, 0, 0))
      ShowPossibleTimeZones(thisTime) 

      thisTime = New DateTimeOffset(#03/10/2007#, New TimeSpan(-6, 0, 0))  
      ShowPossibleTimeZones(thisTime)

      thisTime = New DateTimeOffset(#03/10/2007#, New TimeSpan(+1, 0, 0))
      ShowPossibleTimeZones(thisTime)
   End Sub

   Private Sub ShowPossibleTimeZones(offsetTime As DateTimeOffset)
      Dim offset As TimeSpan = offsetTime.Offset
      Dim timeZones As ReadOnlyCollection(Of TimeZoneInfo)

      Console.WriteLine("{0} could belong to the following time zones:", _
                        offsetTime.ToString())
      ' Get all time zones defined on local system
      timeZones = TimeZoneInfo.GetSystemTimeZones()     
      ' Iterate time zones
      For Each timeZone As TimeZoneInfo In timeZones
         ' Compare offset with offset for that date in that time zone
         If timeZone.GetUtcOffset(offsetTime.DateTime).Equals(offset) Then
            Console.WriteLine("   {0}", timeZone.DisplayName)
         End If   
      Next
      Console.WriteLine()
   End Sub
End Module
' This example displays the following output to the console:
'       6/10/2007 12:00:00 AM -07:00 could belong to the following time zones:
'          (GMT-07:00) Arizona
'          (GMT-08:00) Pacific Time (US & Canada)
'          (GMT-08:00) Tijuana, Baja California
'       
'       3/10/2007 12:00:00 AM -06:00 could belong to the following time zones:
'          (GMT-06:00) Central America
'          (GMT-06:00) Central Time (US & Canada)
'          (GMT-06:00) Guadalajara, Mexico City, Monterrey - New
'          (GMT-06:00) Guadalajara, Mexico City, Monterrey - Old
'          (GMT-06:00) Saskatchewan
'       
'       3/10/2007 12:00:00 AM +01:00 could belong to the following time zones:
'          (GMT+01:00) Amsterdam, Berlin, Bern, Rome, Stockholm, Vienna
'          (GMT+01:00) Belgrade, Bratislava, Budapest, Ljubljana, Prague
'          (GMT+01:00) Brussels, Copenhagen, Madrid, Paris
'          (GMT+01:00) Sarajevo, Skopje, Warsaw, Zagreb
'          (GMT+01:00) West Central Africa
using System;
using System.Collections.ObjectModel;

public class TimeOffsets
{
   public static void Main()
   {
      DateTime thisDate = new DateTime(2007, 3, 10, 0, 0, 0);
      DateTime dstDate = new DateTime(2007, 6, 10, 0, 0, 0);
      DateTimeOffset thisTime;

      thisTime = new DateTimeOffset(dstDate, new TimeSpan(-7, 0, 0));
      ShowPossibleTimeZones(thisTime);

      thisTime = new DateTimeOffset(thisDate, new TimeSpan(-6, 0, 0));  
      ShowPossibleTimeZones(thisTime);

      thisTime = new DateTimeOffset(thisDate, new TimeSpan(+1, 0, 0));
      ShowPossibleTimeZones(thisTime);
   }

   private static void ShowPossibleTimeZones(DateTimeOffset offsetTime)
   {
      TimeSpan offset = offsetTime.Offset;
      ReadOnlyCollection<TimeZoneInfo> timeZones;

      Console.WriteLine("{0} could belong to the following time zones:", 
                        offsetTime.ToString());
      // Get all time zones defined on local system
      timeZones = TimeZoneInfo.GetSystemTimeZones();     
      // Iterate time zones 
      foreach (TimeZoneInfo timeZone in timeZones)
      {
         // Compare offset with offset for that date in that time zone
         if (timeZone.GetUtcOffset(offsetTime.DateTime).Equals(offset))
            Console.WriteLine("   {0}", timeZone.DisplayName);
      }
      Console.WriteLine();
   } 
}
// This example displays the following output to the console:
//       6/10/2007 12:00:00 AM -07:00 could belong to the following time zones:
//          (GMT-07:00) Arizona
//          (GMT-08:00) Pacific Time (US & Canada)
//          (GMT-08:00) Tijuana, Baja California
//       
//       3/10/2007 12:00:00 AM -06:00 could belong to the following time zones:
//          (GMT-06:00) Central America
//          (GMT-06:00) Central Time (US & Canada)
//          (GMT-06:00) Guadalajara, Mexico City, Monterrey - New
//          (GMT-06:00) Guadalajara, Mexico City, Monterrey - Old
//          (GMT-06:00) Saskatchewan
//       
//       3/10/2007 12:00:00 AM +01:00 could belong to the following time zones:
//          (GMT+01:00) Amsterdam, Berlin, Bern, Rome, Stockholm, Vienna
//          (GMT+01:00) Belgrade, Bratislava, Budapest, Ljubljana, Prague
//          (GMT+01:00) Brussels, Copenhagen, Madrid, Paris
//          (GMT+01:00) Sarajevo, Skopje, Warsaw, Zagreb
//          (GMT+01:00) West Central Africa

從輸出可以看到,這個範例中的每個日期和時間值都可能屬於至少三個不同的時區。 DateTimeOffset 值 6/10/2007 顯示,如果日期和時間值表示的是日光節約時間,它與 UTC 之間的位移甚至不一定相當於原始時區的基礎 UTC 位移,或是與其顯示名稱找到的 UTC 之間的位移。 這表示,由於單一 DateTimeOffset 值並未與其時區緊密連結,因此無法反映出時區與日光節約時間的來回轉換。 當使用日期和時間計算 DateTimeOffset 值的時候,問題就更為明顯 (如需如何在執行日期和時間運算時,將時區的調整規則列入考量的討論,請參閱使用日期和時間執行算術運算)。

TimeZoneInfo 類別

TimeZoneInfo 類別可表示全球任何時區,並可將某一時區的任何日期和時間轉換成另一個時區的日期和時間。 TimeZoneInfo 類別可在使用日期和時間時,讓任何日期和時間值都明確識別某個單一時間點。 TimeZoneInfo 類別也是可以延伸的。 雖然它依賴提供給 Windows 系統以及定義在登錄中的時間資訊,但也支援建立自訂時區。 此外也支援時區資訊的序列化和還原序列化。

在某些情況下,要完整利用 TimeZoneInfo 類別,可能需要額外的開發工作。 首先,日期和時間值並未與其所屬時區緊密結合。 因此,除非應用程式提供機制來將日期和時間與其相關時區連結,否則特定日期和時間值就很容易切斷與其時區的關聯 (連結此資訊的其中一個方法是定義類別或結構,其中同時包含日期和時間值以及其相關的時區物件)。其次,Windows XP 和更早的 Windows 版本並沒有針對歷史時區資訊提供支援,而 Windows Vista 的支援則有限。 設計處理歷史日期和時間的應用程式勢必要使用大量的自訂時區。

要利用 .NET Framework 中的時區支援,就必須在具現化日期和時間物件時,知道日期和時間值屬於哪一個時區。 但通常情形並非如此,尤其是在 Web 或網路應用程式中。

請參閱

其他資源

日期、時間和時區