共用方式為


HOW TO:在日期和時間運算中使用時區

更新:2007 年 11 月

通常,當您使用 DateTimeDateTimeOffset 值執行日期與時間算術時,結果並不會反映任何時區調整規則。即使日期與時間值的時區明顯可識別也一樣 (例如,當 Kind 屬性設定為 Local 時)。本主題說明如何對特定時區所屬的日期與時間值,執行算術運算。算術運算的結果會反映時區的調整規則。

將調整規則套用至日期與時間算術

  1. 實作某個將日期與時間值和其所屬的時區緊密結合的方法。例如,宣告一個內含日期與時間值以及所屬時區的結構。下列範例使用這個方法,將 DateTime 值連結至所屬的時區。

    ' Define a structure for DateTime values for internal use only
    Friend Structure TimeWithTimeZone
       Dim TimeZone As TimeZoneInfo
       Dim Time As Date
    End Structure
    
    // Define a structure for DateTime values for internal use only
    internal struct TimeWithTimeZone
    {
       TimeZoneInfo TimeZone;
       DateTime Time;
    }
    
  2. 呼叫 ConvertTimeToUtcConvertTime 方法,將時間轉換成 Coordinated Universal Time (UTC)。

  3. 對 UTC 時間執行算術運算。

  4. 呼叫 TimeZoneInfo.ConvertTime(DateTime, TimeZoneInfo) 方法,將時間從 UTC 轉換成原始時間相關的時區。

範例

下列範例會增加兩小時又三十分鐘至「中央標準時間」2008 年 3 月 9 日,1:30 A.M.。時區轉換為日光節約時間會在三十分鐘後執行,即 2008 年 3 月 9 日 2:00 A.M.。因為本範例遵照上一節所列的四個步驟,所以會正確的回報結果為 2008 年 3 月 9 日 5:00 A.M.。

Public Structure TimeZoneTime
   Public TimeZone As TimeZoneInfo
   Public Time As Date

   Public Sub New(tz As TimeZoneInfo, time As Date)
      If tz Is Nothing Then _
         Throw New ArgumentNullException("The time zone cannot be a null reference.")

      Me.TimeZone = tz
      Me.Time = time
   End Sub

   Public Function AddTime(interval As TimeSpan) As TimeZoneTime
      ' Convert time to UTC
      Dim utcTime As DateTime = TimeZoneInfo.ConvertTimeToUtc(Me.Time, _
                                                              Me.TimeZone)      
      ' Add time interval to time
      utcTime = utcTime.Add(interval)
      ' Convert time back to time in time zone
      Return New TimeZoneTime(Me.TimeZone, TimeZoneInfo.ConvertTime(utcTime, _
                              TimeZoneInfo.Utc, Me.TimeZone))
   End Function
End Structure

Module TimeArithmetic
   Public Const tzName As String = "Central Standard Time"

   Public Sub Main()
      Try
         Dim cstTime1, cstTime2 As TimeZoneTime

         Dim cst As TimeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById(tzName)
         Dim time1 As Date = #03/09/2008 1:30AM#
         Dim twoAndAHalfHours As New TimeSpan(2, 30, 0)

         cstTime1 = New TimeZoneTime(cst, time1)
         cstTime2 = cstTime1.AddTime(twoAndAHalfHours)

         Console.WriteLine("{0} + {1} hours = {2}", cstTime1.Time, _
                                                    twoAndAHalfHours.ToString(), _ 
                                                    cstTime2.Time)  
      Catch
         Console.WriteLine("Unable to find {0}.", tzName)
      End Try   
   End Sub   
End Module
using System;

public struct TimeZoneTime
{
   public TimeZoneInfo TimeZone;
   public DateTime Time;

   public TimeZoneTime(TimeZoneInfo tz, DateTime time)
   {
      if (tz == null) 
         throw new ArgumentNullException("The time zone cannot be a null reference.");

      this.TimeZone = tz;
      this.Time = time;   
   }

   public TimeZoneTime AddTime(TimeSpan interval)
   {
      // Convert time to UTC
      DateTime utcTime = TimeZoneInfo.ConvertTimeToUtc(this.Time, this.TimeZone);
      // Add time interval to time
      utcTime = utcTime.Add(interval);
      // Convert time back to time in time zone
      return new TimeZoneTime(this.TimeZone, TimeZoneInfo.ConvertTime(utcTime, 
                              TimeZoneInfo.Utc, this.TimeZone));
   }
}

public class TimeArithmetic
{
   public const string tzName = "Central Standard Time";

   public static void Main()
   {
      try
      {
         TimeZoneTime cstTime1, cstTime2;

         TimeZoneInfo cst = TimeZoneInfo.FindSystemTimeZoneById(tzName);
         DateTime time1 = new DateTime(2008, 3, 9, 1, 30, 0);          
         TimeSpan twoAndAHalfHours = new TimeSpan(2, 30, 0);

         cstTime1 = new TimeZoneTime(cst, time1);
         cstTime2 = cstTime1.AddTime(twoAndAHalfHours);
         Console.WriteLine("{0} + {1} hours = {2}", cstTime1.Time, 
                                                    twoAndAHalfHours.ToString(),  
                                                    cstTime2.Time);
      }
      catch
      {
         Console.WriteLine("Unable to find {0}.", tzName);
      }
   }
}

DateTimeDateTimeOffset 值都和所屬的時區失去關聯。如果要執行自動套用時區調整規則的日期與時間算術,則日期與時間所屬的時區必須立即可識別。也就是說,日期與時間和相關的時區必須緊密的結合。有幾個方法可以這麼做,包括:

  • 假設應用程式使用的所有時間都屬於特定時區。雖然這個方法有時適用,但是彈性有限而且可能也有可攜性的限制。

  • 定義一個型別,將日期與時間和其關聯的時區納入成為型別的欄位,以緊密的結合日期與時間和其時區。程式碼範例就是使用這個方法,定義一個結構將日期與時間和時區儲存在兩個成員欄位中。

本範例說明如何對 DateTime 值執行算數運算,將時區調整規則套用至結果。但是,DateTimeOffset 值的使用也可以很簡單。下列範例說明如何改寫原始範例中的程式碼,以使用 DateTimeOffset 而不使用 DateTime 值。

Public Structure TimeZoneTime
   Public TimeZone As TimeZoneInfo
   Public Time As DateTimeOffset

   Public Sub New(tz As TimeZoneInfo, time As DateTimeOffset)
      If tz Is Nothing Then _
         Throw New ArgumentNullException("The time zone cannot be a null reference.")

      Me.TimeZone = tz
      Me.Time = time
   End Sub

   Public Function AddTime(interval As TimeSpan) As TimeZoneTime
      ' Convert time to UTC
      Dim utcTime As DateTimeOffset = TimeZoneInfo.ConvertTime(Me.Time, TimeZoneInfo.Utc)      
      ' Add time interval to time
      utcTime = utcTime.Add(interval)
      ' Convert time back to time in time zone
      Return New TimeZoneTime(Me.TimeZone, TimeZoneInfo.ConvertTime(utcTime, Me.TimeZone))
   End Function
End Structure

Module TimeArithmetic
   Public Const tzName As String = "Central Standard Time"

   Public Sub Main()
      Try
         Dim cstTime1, cstTime2 As TimeZoneTime

         Dim cst As TimeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById(tzName)
         Dim time1 As Date = #03/09/2008 1:30AM#
         Dim twoAndAHalfHours As New TimeSpan(2, 30, 0)

         cstTime1 = New TimeZoneTime(cst, _
                        New DateTimeOffset(time1, cst.GetUtcOffset(time1)))
         cstTime2 = cstTime1.AddTime(twoAndAHalfHours)

         Console.WriteLine("{0} + {1} hours = {2}", cstTime1.Time, _
                                                    twoAndAHalfHours.ToString(), _ 
                                                    cstTime2.Time)  
      Catch
         Console.WriteLine("Unable to find {0}.", tzName)
      End Try   
   End Sub   
End Module
using System;

public struct TimeZoneTime
{
   public TimeZoneInfo TimeZone;
   public DateTimeOffset Time;

   public TimeZoneTime(TimeZoneInfo tz, DateTimeOffset time)
   {
      if (tz == null) 
         throw new ArgumentNullException("The time zone cannot be a null reference.");

      this.TimeZone = tz;
      this.Time = time;   
   }

   public TimeZoneTime AddTime(TimeSpan interval)
   {
      // Convert time to UTC
      DateTimeOffset utcTime = TimeZoneInfo.ConvertTime(this.Time, TimeZoneInfo.Utc);      
      // Add time interval to time
      utcTime = utcTime.Add(interval);
      // Convert time back to time in time zone
      return new TimeZoneTime(this.TimeZone, TimeZoneInfo.ConvertTime(utcTime, this.TimeZone));
   }
}

public class TimeArithmetic
{
   public const string tzName = "Central Standard Time";

   public static void Main()
   {
      try
      {
         TimeZoneTime cstTime1, cstTime2;

         TimeZoneInfo cst = TimeZoneInfo.FindSystemTimeZoneById(tzName);
         DateTime time1 = new DateTime(2008, 3, 9, 1, 30, 0);          
         TimeSpan twoAndAHalfHours = new TimeSpan(2, 30, 0);

         cstTime1 = new TimeZoneTime(cst, 
                        new DateTimeOffset(time1, cst.GetUtcOffset(time1)));
         cstTime2 = cstTime1.AddTime(twoAndAHalfHours);
         Console.WriteLine("{0} + {1} hours = {2}", cstTime1.Time, 
                                                    twoAndAHalfHours.ToString(),  
                                                    cstTime2.Time);
      }
      catch
      {
         Console.WriteLine("Unable to find {0}.", tzName);
      }
   }
}

請注意,如果沒有先將 DateTimeOffset 值轉換成 UTC 就執行這個動作,產生的結果會反映正確的時間點,但位移並不會反映指定給這個時間的時區。

編譯程式碼

這個範例需要:

  • 將 System.Core.dll 的參考加入至專案中。

  • 以 using 陳述式 (C# 程式碼中的必要項) 匯入 System 命名空間。

請參閱

概念

使用日期和時間執行算術運算

其他資源

時間和時區