在各時區間轉換時間
更新: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 屬性 |
轉換 |
---|---|
將當地時間轉換成 UTC。 |
|
假設 dateTime 參數為當地時間,並將當地時間轉換成 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.ToUniversalTime 和 DateTime.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.Local 但 TimeZoneInfo 物件卻不代表當地時區,或如果 Kind 屬性為 DateTimeKind.Utc 但 TimeZoneInfo 物件並不等於 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。必須是 DateTime 值,且它的 Kind 屬性設定為 DateTimeKind.Utc 或 DateTimeKind.Unspecified。
要轉換 UTC 的目標時區。
下列程式碼會將 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) 方法中的任何一個,在任兩個時區之間轉換。
-
這個方法的參數分別是要轉換的日期與時間值、TimeZoneInfo 物件代表日期與時間值的時區,以及 TimeZoneInfo 物件代表日期與時間值的轉換目標時區。
-
這個方法的參數是要轉換的日期與時間值、日期與時間值的時區之識別項,以及日期與時間值的轉換目標時區之識別項。
這兩個方法都需要待轉換的日期與時間值的 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;
}
}