共用方式為


在各時區間轉換時間

更新:2007 年 11 月

對於任何具有日期與時間功能的應用程式而言,處理不同時區的功能變得越來越重要。應用程式已不能再假設,所有時間都可以顯示成 DateTime 結構所提供的當地時間。例如,網頁如果顯示美國的東部時間,對東亞地區的客戶而言就不具有公信力。本主題說明如何將時間從一個時區轉換成另一個時區,以及如何轉換有限制時區感知的 DateTimeOffset 值。

轉換成 Coordinated Universal Time

Coordinated Universal Time (UTC) 是高度精確的原子時間標準。全世界的時區都是以 UTC 的正/負位移所表示的。因此 UTC 是一種無時區,或中立時區的時間。如果不同電腦中的日期與時間的可攜性十分重要,建議使用 UTC (如需使用日期與時間的詳細資訊及最佳作法,請參閱使用 .NET Framework 中的 DateTime 的編碼最佳作法)。將個別時區轉換成 UTC,可以使時間的比較變得更簡單。

注意事項:

您也可以將 DateTimeOffset 結構序列化,以明確的表示單一時間點。因為 DateTimeOffset 物件會將日期與時間值及其 UTC 的位移值一起儲存,所以永遠都是表示相對於 UTC 的特定時間點。

將時間轉換成 UTC 最簡單的方式,就是呼叫 static (Visual Basic 中為 Shared) TimeZoneInfo.ConvertTimeToUtc(DateTime) 方法。這個方法實際執行的轉換,會視 dateTime 參數的 Kind 屬性值而定,如下表的說明。

DateTime.Kind 屬性

轉換

DateTimeKind.Local

將當地時間轉換成 UTC。

DateTimeKind.Unspecified

假設 dateTime 參數為當地時間,並將當地時間轉換成 UTC。

DateTimeKind.Utc

傳回未變更的 dateTime 參數。

下列程式碼會將當地時間轉換成 UTC,並將結果顯示在主控台。

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

TimeZoneInfo.ConvertTimeToUtc(DateTime) 方法所產生的結果不一定會與 TimeZone.ToUniversalTimeDateTime.ToUniversalTime 方法相同。如果主機系統的本地時區包含多個調整規則,TimeZoneInfo.ConvertTimeToUtc(DateTime) 就會將適當的規則套用到特定的日期和時間。另外兩個方法則一律套用最新的調整規則。

如果日期與時間值無法表示當地時間或 UTC,則 ToUniversalTime 方法可能會傳回錯誤的結果。但是,您可以使用 TimeZoneInfo.ConvertTimeToUtc 方法,轉換指定的時區之日期與時間 (如需擷取代表目的地時區的 TimeZoneInfo 物件的詳細資訊,請參閱尋找定義於本機系統的時區)。下列程式碼使用 TimeZoneInfo.ConvertTimeToUtc 方法,將「東部標準時間」轉換成 UTC。

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                           
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 {0} UTC.", 
                     TimeZoneInfo.ConvertTimeToUtc(easternTime, easternZone));
}
catch (TimeZoneNotFoundException)
{
   Console.WriteLine("Unable to find the {0} zone in the registry.", 
                     easternZoneId);
}                           
catch (InvalidTimeZoneException)
{
   Console.WriteLine("Registry data on the {0} zone has been corrupted.", 
                     easternZoneId);
}

請注意如果 DateTime 物件的 Kind 屬性和時區不相符,這個方法會擲出 ArgumentException。如果 Kind 屬性為 DateTimeKind.LocalTimeZoneInfo 物件卻不代表當地時區,或如果 Kind 屬性為 DateTimeKind.UtcTimeZoneInfo 物件並不等於 DateTimeKind.Utc 時,就會發生不相符的情形。

這些方法全部都使用 DateTime 值為參數,並傳回一個 DateTime 值。如果是 DateTimeOffset 值,DateTimeOffset 結構有一個 ToUniversalTime 執行個體方法,會將目前執行個體的日期與時間轉換成 UTC。下列範例會呼叫 ToUniversalTime 方法,將當地時間及幾個其他時間轉換成 Coordinated Universal Time (UTC)。

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   
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: {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 轉換成「中央標準時間」。

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
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.");
}

將 UTC 轉換成當地時間

如果要將 UTC 轉換成當地時間,請呼叫您要轉換時間之 DateTime 物件的 ToLocalTime 方法。方法的實際行為,會視物件的 Kind 屬性值而定,如下表的說明。

DateTime.Kind 屬性

轉換

DateTimeKind.Local

傳回未變更的 DateTime 值。

DateTimeKind.Unspecified

假設 DateTime 值是 UTC,並將 UTC 轉換為當地時間。

DateTimeKind.Utc

DateTime 值轉換成當地時間。

注意TimeZone.ToLocalTime 方法的行為和 DateTime.ToLocalTime 方法完全相同。這個方法會使用一個參數,也就是要轉換的日期與時間。

您也可以使用 static (在 Visual Basic 中為 Shared) TimeZoneInfo.ConvertTime 方法,將任何指定的時區時間轉換成當地時間。使用的方法在下一節中將詳細說明。

在任兩個時區之間轉換

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

  • ConvertTime

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

  • ConvertTimeBySystemTimeZoneId

    這個方法的參數是要轉換的日期與時間值、日期與時間值的時區之識別項,以及日期與時間值的轉換目標時區之識別項。

這兩個方法都需要待轉換的日期與時間值的 Kind 屬性,以及 TimeZoneInfo 物件或代表彼此對應的時區識別項。否則會擲回 ArgumentException。例如,如果日期與時間值的 Kind 屬性是 DateTimeKind.Local,而當做參數傳送給方法的 TimeZoneInfo 物件不等於 TimeZoneInfo.Local 時,就會擲回例外狀況。如果當做參數傳送給方法的識別項不等於 TimeZoneInfo.Local.Id,也會擲回例外狀況。

下列範例使用 ConvertTime 方法,將夏威夷標準時間轉換為當地時間。

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                     
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.");
}

轉換 DateTimeOffset 值

DateTimeOffset 物件所代表的日期與時間值並不完全是時區感知的,因為在個體化時物件和所在的時區失去關聯。但是,很多情況下,應用程式只需要根據兩個不同的 UTC 位移,而不需要特定的時區時間,就能夠轉換日期與時間。如果要執行這項轉換,可以呼叫目前執行個體的 ToOffset 方法。這個方法的參數,就是方法將傳回之新日期與時間值的位移。

例如,如果已知使用者要求的網頁之日期與時間,且已序列化成 MM/dd/yyyy hh:mm:ss zzzz 格式的字串,則下列 ReturnTimeOnServer 方法會將這個日期與時間值轉換成網頁伺服器上的日期與時間。

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
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;
   }
}

如果該方法傳送字串 "9/1/2007 5:32:07 -05:00",代表比 UTC 早五個小時的時區之時間,就會傳回 9/1/2007 3:32:07 AM -07:00,代表位於美國「太平洋標準時間」區的伺服器。

TimeZoneInfo 類別也包含 TimeZoneInfo.ConvertTime(DateTimeOffset, TimeZoneInfo) 方法的多載,以 DateTimeOffset 值執行時區轉換。這個方法的參數是一個 DateTimeOffset 值,以及一個待轉換時區的參考。這個方法呼叫會傳回 DateTimeOffset 值。可以將上一個範例中的 ReturnTimeOnServer 方法重新撰寫如下以呼叫 ConvertTime(DateTimeOffset, TimeZoneInfo) 方法。

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
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;
   }
}

請參閱

概念

尋找定義於本機系統的時區

參考

TimeZoneInfo

其他資源

時間和時區