共用方式為


在時區之間轉換時間

對於處理時區間差異的任何應用程式而言,它變得越來越重要。 應用程式無法再假設所有時間都可以在當地時間表示,這是從 DateTime 結構取得的時間。 例如,顯示美國東部目前時間的網頁將缺乏對東亞客戶的信任度。 本文說明如何將時間從某個時區轉換到另一個時區,並轉換具有有限時區感知的DateTimeOffset值。

轉換成國際標準時間

世界協調時間(UTC)是高精確度的原子時間標準。 世界時區會以UTC的正或負位移表示。 因此,UTC 提供不受時區限制或時區中立的時間。 當日期和時間跨計算機可移植性很重要時,建議使用UTC。 如需使用日期和時間的詳細數據和其他最佳做法,請參閱 在 .NET Framework 中使用 DateTime 撰寫最佳做法。 將個別時區轉換成UTC可讓時間比較變得簡單。

備註

您也可以串行化 DateTimeOffset 結構,以明確表示單一時間點。 由於 DateTimeOffset 物件會儲存日期和時間值及其與UTC的位移,因此它們一律代表與UTC相關的特定時間點。

將時間轉換成 UTC 最簡單的方式是呼叫 staticShared 在 Visual Basic 中) TimeZoneInfo.ConvertTimeToUtc(DateTime) 方法。 方法所執行的確切轉換取決於 dateTime 參數 Kind 的 屬性值,如下表所示:

DateTime.Kind 轉換
DateTimeKind.Local 將當地時間轉換為UTC。
DateTimeKind.Unspecified 假設 dateTime 參數是當地時間,並將當地時間轉換為UTC。
DateTimeKind.Utc dateTime傳回未變更的參數。

下列程式代碼會將目前的當地時間轉換為UTC,並將結果顯示至主控台:

DateTime dateNow = DateTime.Now;
Console.WriteLine($"The date and time are {TimeZoneInfo.ConvertTimeToUtc(dateNow)} UTC.");
Dim dateNow As Date = Date.Now
Console.WriteLine("The date and time are {0} UTC.", _
                  TimeZoneInfo.ConvertTimeToUtc(dateNow))

如果日期和時間值不代表當地時間或 UTC,此方法 ToUniversalTime 可能會傳回錯誤的結果。 不過,您可以使用 TimeZoneInfo.ConvertTimeToUtc 方法,從指定的時區轉換日期和時間。 如需擷取 TimeZoneInfo 代表目的地時區的物件的詳細資訊,請參閱 尋找本機系統上定義的時區。 下列程式代碼會 TimeZoneInfo.ConvertTimeToUtc 使用 方法,將東部標準時間轉換為UTC:

DateTime easternTime = new DateTime(2007, 01, 02, 12, 16, 00);
string easternZoneId = "Eastern Standard Time";
try
{
    TimeZoneInfo easternZone = TimeZoneInfo.FindSystemTimeZoneById(easternZoneId);
    Console.WriteLine($"The date and time are {TimeZoneInfo.ConvertTimeToUtc(easternTime, easternZone)} UTC.");
}
catch (TimeZoneNotFoundException)
{
    Console.WriteLine($"Unable to find the {easternZoneId} zone in the registry.");
}
catch (InvalidTimeZoneException)
{
    Console.WriteLine($"Registry data on the {easternZoneId} zone has been corrupted.");
}
Dim easternTime As New Date(2007, 01, 02, 12, 16, 00)
Dim easternZoneId As String = "Eastern Standard Time"
Try
    Dim easternZone As TimeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById(easternZoneId)
    Console.WriteLine("The date and time are {0} UTC.", _
                      TimeZoneInfo.ConvertTimeToUtc(easternTime, easternZone))
Catch e As TimeZoneNotFoundException
    Console.WriteLine("Unable to find the {0} zone in the registry.", _
                      easternZoneId)
Catch e As InvalidTimeZoneException
    Console.WriteLine("Registry data on the {0} zone has been corrupted.", _
                      easternZoneId)
End Try

如果TimeZoneInfo.ConvertTimeToUtc物件的ArgumentException屬性與時區不符,方法DateTime會擲回Kind。 如果 Kind 屬性是 DateTimeKind.Local ,但 TimeZoneInfo 物件不代表本機時區,或者 Kind 如果 屬性是 DateTimeKind.Utc ,但 TimeZoneInfo 物件不等於 TimeZoneInfo.Utc,就會發生不相符的情況。

所有這些方法都會接受 DateTime 值做為參數,並傳 DateTime 回值。 針對 DateTimeOffset 值,結構 DateTimeOffset 具有 ToUniversalTime 實例方法,可將目前實例的日期和時間轉換為UTC。 下列範例會呼叫 ToUniversalTime 方法,將當地時間和其他數次轉換成UTC:

DateTimeOffset localTime, otherTime, universalTime;

// Define local time in local time zone
localTime = new DateTimeOffset(new DateTime(2007, 6, 15, 12, 0, 0));
Console.WriteLine($"Local time: {localTime}");
Console.WriteLine();

// Convert local time to offset 0 and assign to otherTime
otherTime = localTime.ToOffset(TimeSpan.Zero);
Console.WriteLine($"Other time: {otherTime}");
Console.WriteLine($"{localTime} = {otherTime}: {localTime.Equals(otherTime)}");
Console.WriteLine($"{localTime} exactly equals {otherTime}: {localTime.EqualsExact(otherTime)}");
Console.WriteLine();

// Convert other time to UTC
universalTime = localTime.ToUniversalTime();
Console.WriteLine($"Universal time: {universalTime}");
Console.WriteLine($"{otherTime} = {universalTime}: {universalTime.Equals(otherTime)}");
Console.WriteLine($"{otherTime} exactly equals {universalTime}: {universalTime.EqualsExact(otherTime)}");
Console.WriteLine();

// The example produces the following output to the console:
//    Local time: 6/15/2007 12:00:00 PM -07:00
//
//    Other time: 6/15/2007 7:00:00 PM +00:00
//    6/15/2007 12:00:00 PM -07:00 = 6/15/2007 7:00:00 PM +00:00: True
//    6/15/2007 12:00:00 PM -07:00 exactly equals 6/15/2007 7:00:00 PM +00:00: False
//
//    Universal time: 6/15/2007 7:00:00 PM +00:00
//    6/15/2007 7:00:00 PM +00:00 = 6/15/2007 7:00:00 PM +00:00: True
//    6/15/2007 7:00:00 PM +00:00 exactly equals 6/15/2007 7:00:00 PM +00:00: True
Dim localTime, otherTime, universalTime As DateTimeOffset

' Define local time in local time zone
localTime = New DateTimeOffset(#6/15/2007 12:00:00PM#)
Console.WriteLine("Local time: {0}", localTime)
Console.WriteLine()

' Convert local time to offset 0 and assign to otherTime
otherTime = localTime.ToOffset(TimeSpan.Zero)
Console.WriteLine("Other time: {0}", otherTime)
Console.WriteLine("{0} = {1}: {2}", _
                  localTime, otherTime, _
                  localTime.Equals(otherTime))
Console.WriteLine("{0} exactly equals {1}: {2}", _
                  localTime, otherTime, _
                  localTime.EqualsExact(otherTime))
Console.WriteLine()

' Convert other time to UTC
universalTime = localTime.ToUniversalTime()
Console.WriteLine("Universal time: {0}", universalTime)
Console.WriteLine("{0} = {1}: {2}", _
                  otherTime, universalTime, _
                  universalTime.Equals(otherTime))
Console.WriteLine("{0} exactly equals {1}: {2}", _
                  otherTime, universalTime, _
                  universalTime.EqualsExact(otherTime))
Console.WriteLine()
' The example produces the following output to the console:
'    Local time: 6/15/2007 12:00:00 PM -07:00
'    
'    Other time: 6/15/2007 7:00:00 PM +00:00
'    6/15/2007 12:00:00 PM -07:00 = 6/15/2007 7:00:00 PM +00:00: True
'    6/15/2007 12:00:00 PM -07:00 exactly equals 6/15/2007 7:00:00 PM +00:00: False
'    
'    Universal time: 6/15/2007 7:00:00 PM +00:00
'    6/15/2007 7:00:00 PM +00:00 = 6/15/2007 7:00:00 PM +00:00: True
'    6/15/2007 7:00:00 PM +00:00 exactly equals 6/15/2007 7:00:00 PM +00:00: True   

將UTC轉換為指定的時區

若要將 UTC 轉換為當地時間,請參閱下列 將 UTC 轉換為當地時間 一節。 若要將 UTC 轉換為您指定之任何時區的時間,請呼叫 ConvertTimeFromUtc 方法。 方法會採用兩個參數:

  • 要轉換的UTC。 這個值必須是 DateTime 屬性 Kind 設定為 UnspecifiedUtc的值。

  • 要將UTC轉換至的時區。

下列程式代碼會將 UTC 轉換為中央標準時間:

DateTime timeUtc = DateTime.UtcNow;
try
{
    TimeZoneInfo cstZone = TimeZoneInfo.FindSystemTimeZoneById("Central Standard Time");
    DateTime cstTime = TimeZoneInfo.ConvertTimeFromUtc(timeUtc, cstZone);
    Console.WriteLine("The date and time are {0} {1}.",
                      cstTime,
                      cstZone.IsDaylightSavingTime(cstTime) ?
                              cstZone.DaylightName : cstZone.StandardName);
}
catch (TimeZoneNotFoundException)
{
    Console.WriteLine("The registry does not define the Central Standard Time zone.");
}
catch (InvalidTimeZoneException)
{
    Console.WriteLine("Registry data on the Central Standard Time zone has been corrupted.");
}
Dim timeUtc As Date = Date.UtcNow
Try
    Dim cstZone As TimeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById("Central Standard Time")
    Dim cstTime As Date = TimeZoneInfo.ConvertTimeFromUtc(timeUtc, cstZone)
    Console.WriteLine("The date and time are {0} {1}.", _
                      cstTime, _
                      IIf(cstZone.IsDaylightSavingTime(cstTime), _
                          cstZone.DaylightName, cstZone.StandardName))
Catch e As TimeZoneNotFoundException
    Console.WriteLine("The registry does not define the Central Standard Time zone.")
Catch e As InvalidTimeZoneException
    Console.WriteLine("Registry data on the Central Standard Time zone has been corrupted.")
End Try

將UTC轉換為當地時間

若要將 UTC 轉換為當地時間,請呼叫 ToLocalTime 您要轉換其時間的物件 方法 DateTime 。 方法的確切行為取決於物件 Kind 屬性的值,如下表所示:

DateTime.Kind 轉換
DateTimeKind.Local 返回未變更的 DateTime 值。
DateTimeKind.Unspecified 假設 DateTime 此值為 UTC,並將 UTC 轉換為當地時間。
DateTimeKind.Utc DateTime 值轉換為當地時間。

備註

方法 TimeZone.ToLocalTime 的行為與 DateTime.ToLocalTime 方法相同。 它需要單一參數,也就是日期和時間值來轉換。

您也可以使用 staticShared 在 Visual Basic 中) TimeZoneInfo.ConvertTime 方法,將任何指定時區中的時間轉換為當地時間。 下一節將討論這項技術。

在任意兩個時區之間進行轉換

您可以使用static類別的下列兩種方法之一(在 Visual Basic 中為Shared),在任意兩個時區之間進行轉換:

  • ConvertTime

    這個方法的參數是要轉換的日期和時間值、 TimeZoneInfo 代表日期和時間值的時區的物件,以及 TimeZoneInfo 代表要轉換日期和時間值的時區的物件。

  • ConvertTimeBySystemTimeZoneId

    這個方法的參數是要轉換的日期和時間值、日期和時間值的時區識別符,以及要轉換至的時區識別符。

這兩種方法都需要 Kind 日期和時間值的 屬性才能轉換,以及 TimeZoneInfo 代表其時區的物件或時區標識元彼此對應。 否則會拋出 ArgumentException。 例如,如果Kind日期和時間值的屬性是DateTimeKind.Local,那麼當作為參數傳遞到方法的物件不等於TimeZoneInfo時,就會擲回TimeZoneInfo.Local例外狀況。 當標識符作為參數傳遞到方法不等於 TimeZoneInfo.Local.Id 時,將引發例外。

下列範例會使用 ConvertTime 方法,從夏威夷標準時間轉換成當地時間:

DateTime hwTime = new DateTime(2007, 02, 01, 08, 00, 00);
try
{
    TimeZoneInfo hwZone = TimeZoneInfo.FindSystemTimeZoneById("Hawaiian Standard Time");
    Console.WriteLine("{0} {1} is {2} local time.",
            hwTime,
            hwZone.IsDaylightSavingTime(hwTime) ? hwZone.DaylightName : hwZone.StandardName,
            TimeZoneInfo.ConvertTime(hwTime, hwZone, TimeZoneInfo.Local));
}
catch (TimeZoneNotFoundException)
{
    Console.WriteLine("The registry does not define the Hawaiian Standard Time zone.");
}
catch (InvalidTimeZoneException)
{
    Console.WriteLine("Registry data on the Hawaiian Standard Time zone has been corrupted.");
}
Dim hwTime As Date = #2/01/2007 8:00:00 AM#
Try
    Dim hwZone As TimeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById("Hawaiian Standard Time")
    Console.WriteLine("{0} {1} is {2} local time.", _
                      hwTime, _
                      IIf(hwZone.IsDaylightSavingTime(hwTime), hwZone.DaylightName, hwZone.StandardName), _
                      TimeZoneInfo.ConvertTime(hwTime, hwZone, TimeZoneInfo.Local))
Catch e As TimeZoneNotFoundException
    Console.WriteLine("The registry does not define the Hawaiian Standard Time zone.")
Catch e As InvalidTimeZoneException
    Console.WriteLine("Registry data on the Hawaiian Standard Time zone has been corrupted.")
End Try

轉換 DateTimeOffset 值

物件所 DateTimeOffset 代表的日期和時間值不會完全感知時區,因為物件在具現化時會與其時區解除關聯。 不過,在許多情況下,應用程式只需要根據UTC的兩個不同的位移來轉換日期和時間,而不是在特定時區的時間。 若要執行此轉換,您可以呼叫目前實例的 ToOffset 方法。 方法的單一參數是方法將傳回之新日期和時間值的位移。

例如,如果已知使用者要求網頁的日期和時間,並以MM/dd/yyyy hh:mm:ss zzh 格式串行化為字串,下列 ReturnTimeOnServer 方法會將這個日期和時間值轉換成網頁伺服器上的日期和時間:

public DateTimeOffset ReturnTimeOnServer(string clientString)
{
   string format = @"M/d/yyyy H:m:s zzz";
   TimeSpan serverOffset = TimeZoneInfo.Local.GetUtcOffset(DateTimeOffset.Now);

   try
   {
      DateTimeOffset clientTime = DateTimeOffset.ParseExact(clientString, format, CultureInfo.InvariantCulture);
      DateTimeOffset serverTime = clientTime.ToOffset(serverOffset);
      return serverTime;
   }
   catch (FormatException)
   {
      return DateTimeOffset.MinValue;
   }
}
Public Function ReturnTimeOnServer(clientString As String) As DateTimeOffset
    Dim format As String = "M/d/yyyy H:m:s zzz"
    Dim serverOffset As TimeSpan = TimeZoneInfo.Local.GetUtcOffset(DateTimeOffset.Now)

    Try
        Dim clientTime As DateTimeOffset = DateTimeOffset.ParseExact(clientString, format, CultureInfo.InvariantCulture)
        Dim serverTime As DateTimeOffset = clientTime.ToOffset(serverOffset)
        Return serverTime
    Catch e As FormatException
        Return DateTimeOffset.MinValue
    End Try
End Function

如果方法傳遞字串「9/1/2007 5:32:07 -05:00」,代表一個比 UTC 早五個小時的時區中的日期和時間,對於位於美國太平洋標準時間區的伺服器,它會傳回「9/1/2007 3:32:07 AM -07:00」。

類別 TimeZoneInfo 也包含 TimeZoneInfo.ConvertTime(DateTimeOffset, TimeZoneInfo) 方法的多載,此方法使用 ToOffset(TimeSpan) 值進行時區轉換。 方法的參數是值DateTimeOffset和時間要被轉換到的時區參考。 方法呼叫會傳回DateTimeOffset值。 例如,上一個範例中的 ReturnTimeOnServer 方法可以重寫如下,以呼叫 ConvertTime(DateTimeOffset, TimeZoneInfo) 方法。

public DateTimeOffset ReturnTimeOnServer(string clientString)
{
   string format = @"M/d/yyyy H:m:s zzz";

   try
   {
      DateTimeOffset clientTime = DateTimeOffset.ParseExact(clientString, format,
                                  CultureInfo.InvariantCulture);
      DateTimeOffset serverTime = TimeZoneInfo.ConvertTime(clientTime,
                                  TimeZoneInfo.Local);
      return serverTime;
   }
   catch (FormatException)
   {
      return DateTimeOffset.MinValue;
   }
}
Public Function ReturnTimeOnServer(clientString As String) As DateTimeOffset
    Dim format As String = "M/d/yyyy H:m:s zzz"

    Try
        Dim clientTime As DateTimeOffset = DateTimeOffset.ParseExact(clientString, format, CultureInfo.InvariantCulture)
        Dim serverTime As DateTimeOffset = TimeZoneInfo.ConvertTime(clientTime, TimeZoneInfo.Local)
        Return serverTime
    Catch e As FormatException
        Return DateTimeOffset.MinValue
    End Try
End Function

另請參閱