在 DateTime 和 DateTimeOffset 之間轉換
更新:2007 年 11 月
雖然 DateTimeOffset 結構對時區的感知程度要比 DateTime 結構高,但在方法呼叫中較常使用的卻是 DateTime 參數。因此,知道如何將 DateTimeOffset 值與 DateTime 值相互轉換,就十分重要。本主題說明如何執行這些轉換,同時盡可能保留時區資訊。
注意事項: |
---|
無論是使用 DateTime 或 DateTimeOffset 型別來表示時區中的時間,都會受到某些限制。透過 DateTime 的 Kind 屬性,只能反映 Coordinated Universal Time (UTC) 和系統的當地時區。DateTimeOffset 雖然可以反映時間的 UTC 位移,但無法反映位移所屬的實際時區為何。如需時間值和時區支援的詳細資訊,請參閱在 DateTime、DateTimeOffset 和 TimeZoneInfo 之間選擇。 |
從 DateTime 轉換為 DateTimeOffset
DateTimeOffset 結構提供兩種對等的方法來執行 DateTime 至 DateTimeOffset 的轉換,這兩種方法可處理大部分的轉換:
DateTimeOffset 建構函式,會根據 DateTime 值來建立新的 DateTimeOffset 物件。
隱含轉換運算子,可以讓您將 DateTime 值指派給 DateTimeOffset 物件。
針對 UTC 和本地 DateTime 值,所產生之 DateTimeOffset 值的 Offset 屬性會準確地反映出 UTC 或本地時區位移。例如,下列程式碼會將 UTC 時間轉換成其對等的 DateTimeOffset 值。
Dim utcTime1 As Date = Date.SpecifyKind(#06/19/2008 7:00AM#, _
DateTimeKind.Utc)
Dim utcTime2 As DateTimeOffset = utcTime1
Console.WriteLine("Converted {0} {1} to a DateTimeOffset value of {2}", _
utcTime1, _
utcTime1.Kind.ToString(), _
utcTime2)
' This example displays the following output to the console:
' Converted 6/19/2008 7:00:00 AM Utc to a DateTimeOffset value of 6/19/2008 7:00:00 AM +00:00
DateTime utcTime1 = new DateTime(2008, 6, 19, 7, 0, 0);
utcTime1 = DateTime.SpecifyKind(utcTime1, DateTimeKind.Utc);
DateTimeOffset utcTime2 = utcTime1;
Console.WriteLine("Converted {0} {1} to a DateTimeOffset value of {2}",
utcTime1,
utcTime1.Kind.ToString(),
utcTime2);
// This example displays the following output to the console:
// Converted 6/19/2008 7:00:00 AM Utc to a DateTimeOffset value of 6/19/2008 7:00:00 AM +00:00
在此例中,utcTime2 變數的位移為 00:00。同樣地,下列程式碼會將本地時間轉換成其對等的 DateTimeOffset 值。
Dim localTime1 As Date = Date.SpecifyKind(#06/19/2008 7:00AM#, DateTimeKind.Local)
Dim localTime2 As DateTimeOffset = localTime1
Console.WriteLine("Converted {0} {1} to a DateTimeOffset value of {2}", _
localTime1, _
localTime1.Kind.ToString(), _
localTime2)
' This example displays the following output to the console:
' Converted 6/19/2008 7:00:00 AM Local to a DateTimeOffset value of 6/19/2008 7:00:00 AM -07:00
DateTime localTime1 = new DateTime(2008, 6, 19, 7, 0, 0);
localTime1 = DateTime.SpecifyKind(localTime1, DateTimeKind.Local);
DateTimeOffset localTime2 = localTime1;
Console.WriteLine("Converted {0} {1} to a DateTimeOffset value of {2}",
localTime1,
localTime1.Kind.ToString(),
localTime2);
// This example displays the following output to the console:
// Converted 6/19/2008 7:00:00 AM Local to a DateTimeOffset value of 6/19/2008 7:00:00 AM -07:00
不過,對於 Kind 屬性為 DateTimeKind.Unspecified 的 DateTime 值,這兩種轉換方法都會產生其位移為本地時區位移的 DateTimeOffset 值。這會在下列範例中示範,此範例執行的時區為美國太平洋標準時間。
Dim time1 As Date = #06/19/2008 7:00AM# ' Kind is DateTimeKind.Unspecified
Dim time2 As DateTimeOffset = time1
Console.WriteLine("Converted {0} {1} to a DateTimeOffset value of {2}", _
time1, _
time1.Kind.ToString(), _
time2)
' This example displays the following output to the console:
' Converted 6/19/2008 7:00:00 AM Unspecified to a DateTimeOffset value of 6/19/2008 7:00:00 AM -07:00
DateTime time1 = new DateTime(2008, 6, 19, 7, 0, 0); // Kind is DateTimeKind.Unspecified
DateTimeOffset time2 = time1;
Console.WriteLine("Converted {0} {1} to a DateTimeOffset value of {2}",
time1,
time1.Kind.ToString(),
time2);
// This example displays the following output to the console:
// Converted 6/19/2008 7:00:00 AM Unspecified to a DateTimeOffset value of 6/19/2008 7:00:00 AM -07:00
如果 DateTime 值反映的日期和時間不是本地時區或 UTC,您可以藉由呼叫多載 DateTimeOffset 建構函式,將它轉換成 DateTimeOffset 值並保留其時區資訊。例如,下列範例會將反映中央標準時間的 DateTimeOffset 物件具現化。
Dim time1 As Date = #06/19/2008 7:00AM# ' Kind is DateTimeKind.Unspecified
Try
Dim time2 As New DateTimeOffset(time1, _
TimeZoneInfo.FindSystemTimeZoneById("Central Standard Time").GetUtcOffset(time1))
Console.WriteLine("Converted {0} {1} to a DateTime value of {2}", _
time1, _
time1.Kind.ToString(), _
time2)
' Handle exception if time zone is not defined in registry
Catch e As TimeZoneNotFoundException
Console.WriteLine("Unable to identify target time zone for conversion.")
End Try
' This example displays the following output to the console:
' Converted 6/19/2008 7:00:00 AM Unspecified to a DateTime value of 6/19/2008 7:00:00 AM -05:00
DateTime time1 = new DateTime(2008, 6, 19, 7, 0, 0); // Kind is DateTimeKind.Unspecified
try
{
DateTimeOffset time2 = new DateTimeOffset(time1,
TimeZoneInfo.FindSystemTimeZoneById("Central Standard Time").GetUtcOffset(time1));
Console.WriteLine("Converted {0} {1} to a DateTime value of {2}",
time1,
time1.Kind.ToString(),
time2);
}
// Handle exception if time zone is not defined in registry
catch (TimeZoneNotFoundException)
{
Console.WriteLine("Unable to identify target time zone for conversion.");
}
// This example displays the following output to the console:
// Converted 6/19/2008 7:00:00 AM Unspecified to a DateTime value of 6/19/2008 7:00:00 AM -05:00
此建構函式多載的第二個參數 (即表示時間之 UTC 位移的 TimeSpan 物件) 應藉由呼叫時間相對應時區的 TimeZoneInfo.GetUtcOffset(DateTime) 方法來擷取。這個方法的單一參數就是 DateTime 值,此值表示要轉換的日期和時間。如果時區支援日光節約時間,則此參數可讓方法判斷該特定日期和時間的適當位移。
從 DateTimeOffset 轉換為 DateTime
DateTime 屬性最常用來執行 DateTimeOffset 至 DateTime 的轉換。不過,它會傳回 Kind 屬性為 Unspecified 的 DateTime 值,如下列範例所示。
Const baseTime As Date = #06/19/2008 7:00AM#
Dim sourceTime As DateTimeOffset
Dim targetTime As Date
' Convert UTC to DateTime value
sourceTime = New DateTimeOffset(baseTime, TimeSpan.Zero)
targetTime = sourceTime.DateTime
Console.WriteLine("{0} converts to {1} {2}", _
sourceTime, _
targetTime, _
targetTime.Kind.ToString())
' Convert local time to DateTime value
sourceTime = New DateTimeOffset(baseTime, _
TimeZoneInfo.Local.GetUtcOffset(baseTime))
targetTime = sourceTime.DateTime
Console.WriteLine("{0} converts to {1} {2}", _
sourceTime, _
targetTime, _
targetTime.Kind.ToString())
' Convert Central Standard Time to a DateTime value
Try
Dim offset As TimeSpan = TimeZoneInfo.FindSystemTimeZoneById("Central Standard Time").GetUtcOffset(baseTime)
sourceTime = New DateTimeOffset(baseTime, offset)
targetTime = sourceTime.DateTime
Console.WriteLine("{0} converts to {1} {2}", _
sourceTime, _
targetTime, _
targetTime.Kind.ToString())
Catch e As TimeZoneNotFoundException
Console.WriteLine("Unable to create DateTimeOffset based on U.S. Central Standard Time.")
End Try
' This example displays the following output to the console:
' 6/19/2008 7:00:00 AM +00:00 converts to 6/19/2008 7:00:00 AM Unspecified
' 6/19/2008 7:00:00 AM -07:00 converts to 6/19/2008 7:00:00 AM Unspecified
' 6/19/2008 7:00:00 AM -05:00 converts to 6/19/2008 7:00:00 AM Unspecified
DateTime baseTime = new DateTime(2008, 6, 19, 7, 0, 0);
DateTimeOffset sourceTime;
DateTime targetTime;
// Convert UTC to DateTime value
sourceTime = new DateTimeOffset(baseTime, TimeSpan.Zero);
targetTime = sourceTime.DateTime;
Console.WriteLine("{0} converts to {1} {2}",
sourceTime,
targetTime,
targetTime.Kind.ToString());
// Convert local time to DateTime value
sourceTime = new DateTimeOffset(baseTime,
TimeZoneInfo.Local.GetUtcOffset(baseTime));
targetTime = sourceTime.DateTime;
Console.WriteLine("{0} converts to {1} {2}",
sourceTime,
targetTime,
targetTime.Kind.ToString());
// Convert Central Standard Time to a DateTime value
try
{
TimeSpan offset = TimeZoneInfo.FindSystemTimeZoneById("Central Standard Time").GetUtcOffset(baseTime);
sourceTime = new DateTimeOffset(baseTime, offset);
targetTime = sourceTime.DateTime;
Console.WriteLine("{0} converts to {1} {2}",
sourceTime,
targetTime,
targetTime.Kind.ToString());
}
catch (TimeZoneNotFoundException)
{
Console.WriteLine("Unable to create DateTimeOffset based on U.S. Central Standard Time.");
}
// This example displays the following output to the console:
// 6/19/2008 7:00:00 AM +00:00 converts to 6/19/2008 7:00:00 AM Unspecified
// 6/19/2008 7:00:00 AM -07:00 converts to 6/19/2008 7:00:00 AM Unspecified
// 6/19/2008 7:00:00 AM -05:00 converts to 6/19/2008 7:00:00 AM Unspecified
這表示當使用 DateTime 屬性時,在轉換之後,關於 DateTimeOffset 值與 UTC 之間關係的任何資訊都將會遺失。這會影響對應至 UTC 時間或系統本地時間的 DateTimeOffset 值,因為 DateTime 結構的 Kind 屬性中只會反映這兩種時區。
為了在轉換 DateTimeOffset 為 DateTime 值時盡可能保留時區資訊,您可以使用 DateTimeOffset.UtcDateTime 和 DateTimeOffset.LocalDateTime 屬性。
轉換 UTC 時間
若要指示轉換的 DateTime 值是 UTC 時間,您可以擷取 DateTimeOffset.UtcDateTime 屬性的值。它在下列兩方面與 DateTime 屬性不同:
注意事項: |
---|
如果您的應用程式需要轉換的 DateTime 值明確識別單一時間點,請考慮使用 DateTimeOffset.UtcDateTime 屬性來處理所有 DateTimeOffset 至 DateTime 的轉換。 |
下列程式碼使用 UtcDateTime 屬性來將位移等於 Zero() 的 DateTimeOffset 值轉換為 DateTime 值。
Dim utcTime1 As New DateTimeOffset(#06/19/2008 7:00AM#, TimeSpan.Zero)
Dim utcTime2 As Date = utcTime1.UtcDateTime
Console.WriteLine("{0} converted to {1} {2}", _
utcTime1, _
utcTime2, _
utcTime2.Kind.ToString())
' The example displays the following output to the console:
' 6/19/2008 7:00:00 AM +00:00 converted to 6/19/2008 7:00:00 AM Utc
DateTimeOffset utcTime1 = new DateTimeOffset(2008, 6, 19, 7, 0, 0, TimeSpan.Zero);
DateTime utcTime2 = utcTime1.UtcDateTime;
Console.WriteLine("{0} converted to {1} {2}",
utcTime1,
utcTime2,
utcTime2.Kind.ToString());
// The example displays the following output to the console:
// 6/19/2008 7:00:00 AM +00:00 converted to 6/19/2008 7:00:00 AM Utc
下列程式碼使用 UtcDateTime 屬性來對 DateTimeOffset 值同時執行時區轉換和型別轉換。
Dim originalTime As New DateTimeOffset(#6/19/2008 7:00AM#, _
New TimeSpan(5, 0, 0))
Dim utcTime As Date = originalTime.UtcDateTime
Console.WriteLine("{0} converted to {1} {2}", _
originalTime, _
utcTime, _
utcTime.Kind.ToString())
' The example displays the following output to the console:
' 6/19/2008 7:00:00 AM +05:00 converted to 6/19/2008 2:00:00 AM Utc
DateTimeOffset originalTime = new DateTimeOffset(2008, 6, 19, 7, 0, 0, new TimeSpan(5, 0, 0));
DateTime utcTime = originalTime.UtcDateTime;
Console.WriteLine("{0} converted to {1} {2}",
originalTime,
utcTime,
utcTime.Kind.ToString());
// The example displays the following output to the console:
// 6/19/2008 7:00:00 AM +05:00 converted to 6/19/2008 2:00:00 AM Utc
轉換本地時間
若要指示 DateTimeOffset 值表示的是本地時間,您可以將 DateTimeOffset.DateTime 屬性傳回的 DateTime 值傳遞至 static (在 Visual Basic 中為 Shared) SpecifyKind() 方法。這個方法會傳回第一個參數傳遞給它的日期和時間,但其 Kind 屬性會被設為第二個參數所指定的值。下列程式碼使用 SpecifyKind() 方法來轉換值相當於本地時區位移的 DateTimeOffset。
Dim sourceDate As Date = #06/19/2008 7:00AM#
Dim utcTime1 As New DateTimeOffset(sourceDate, _
TimeZoneInfo.Local.GetUtcOffset(sourceDate))
Dim utcTime2 As Date = utcTime1.DateTime
If utcTime1.Offset.Equals(TimeZoneInfo.Local.GetUtcOffset(utcTime1.DateTime)) Then
utcTime2 = DateTime.SpecifyKind(utcTime2, DateTimeKind.Local)
End If
Console.WriteLine("{0} converted to {1} {2}", _
utcTime1, _
utcTime2, _
utcTime2.Kind.ToString())
' The example displays the following output to the console:
' 6/19/2008 7:00:00 AM -07:00 converted to 6/19/2008 7:00:00 AM Local
DateTime sourceDate = new DateTime(2008, 6, 19, 7, 0, 0);
DateTimeOffset utcTime1 = new DateTimeOffset(sourceDate,
TimeZoneInfo.Local.GetUtcOffset(sourceDate));
DateTime utcTime2 = utcTime1.DateTime;
if (utcTime1.Offset.Equals(TimeZoneInfo.Local.GetUtcOffset(utcTime1.DateTime)))
utcTime2 = DateTime.SpecifyKind(utcTime2, DateTimeKind.Local);
Console.WriteLine("{0} converted to {1} {2}",
utcTime1,
utcTime2,
utcTime2.Kind.ToString());
// The example displays the following output to the console:
// 6/19/2008 7:00:00 AM -07:00 converted to 6/19/2008 7:00:00 AM Local
您也可以使用 DateTimeOffset.LocalDateTime 屬性來將 DateTimeOffset 值轉換為本地 DateTime 值。傳回之 DateTime 值的 Kind 屬性為 Local。下列程式碼會使用 DateTimeOffset.LocalDateTime 屬性來轉換值相當於本地時區位移的 DateTimeOffset 值。
Dim sourceDate As Date = #06/19/2008 7:00AM#
Dim localTime1 As New DateTimeOffset(sourceDate, _
TimeZoneInfo.Local.GetUtcOffset(sourceDate))
Dim localTime2 As Date = localTime1.LocalDateTime
Console.WriteLine("{0} converted to {1} {2}", _
localTime1, _
localTime2, _
localTime2.Kind.ToString())
' The example displays the following output to the console:
' 6/19/2008 7:00:00 AM -07:00 converted to 6/19/2008 7:00:00 AM Local
DateTime sourceDate = new DateTime(2008, 6, 19, 7, 0, 0);
DateTimeOffset localTime1 = new DateTimeOffset(sourceDate,
TimeZoneInfo.Local.GetUtcOffset(sourceDate));
DateTime localTime2 = localTime1.LocalDateTime;
Console.WriteLine("{0} converted to {1} {2}",
localTime1,
localTime2,
localTime2.Kind.ToString());
// The example displays the following output to the console:
// 6/19/2008 7:00:00 AM -07:00 converted to 6/19/2008 7:00:00 AM Local
當您使用 DateTimeOffset.LocalDateTime 屬性擷取 DateTime 值時,屬性的 get 存取子會先將 DateTimeOffset 值轉換成 UTC,然後再藉由呼叫 ToLocalTime 方法將它轉換成本地時間。這表示您可以從 DateTimeOffset.LocalDateTime 屬性擷取值來執行時區轉換,並且同時執行型別轉換。這也表示會套用本地時區的調整規則來執行轉換。下列程式碼說明如何使用 DateTimeOffset.LocalDateTime 屬性來同時執行型別和時區轉換。
Dim originalDate As DateTimeOffset
Dim localDate As Date
' Convert time originating in a different time zone
originalDate = New DateTimeOffset(#06/19/2008 7:00AM#, _
New TimeSpan(-5, 0, 0))
localDate = originalDate.LocalDateTime
Console.WriteLine("{0} converted to {1} {2}", _
originalDate, _
localDate, _
localDate.Kind.ToString())
' Convert time originating in a different time zone
' so local time zone's adjustment rules are applied
originalDate = New DateTimeOffset(#11/04/2007 4:00AM#, _
New TimeSpan(-5, 0, 0))
localDate = originalDate.LocalDateTime
Console.WriteLine("{0} converted to {1} {2}", _
originalDate, _
localDate, _
localDate.Kind.ToString())
' The example displays the following output to the console:
' 6/19/2008 7:00:00 AM -05:00 converted to 6/19/2008 5:00:00 AM Local
' 11/4/2007 4:00:00 AM -05:00 converted to 11/4/2007 1:00:00 AM Local
DateTimeOffset originalDate;
DateTime localDate;
// Convert time originating in a different time zone
originalDate = new DateTimeOffset(2008, 6, 18, 7, 0, 0,
new TimeSpan(-5, 0, 0));
localDate = originalDate.LocalDateTime;
Console.WriteLine("{0} converted to {1} {2}",
originalDate,
localDate,
localDate.Kind.ToString());
// Convert time originating in a different time zone
// so local time zone's adjustment rules are applied
originalDate = new DateTimeOffset(2007, 11, 4, 4, 0, 0,
new TimeSpan(-5, 0, 0));
localDate = originalDate.LocalDateTime;
Console.WriteLine("{0} converted to {1} {2}",
originalDate,
localDate,
localDate.Kind.ToString());
// The example displays the following output to the console:
// 6/19/2008 7:00:00 AM -05:00 converted to 6/19/2008 5:00:00 AM Local
// 11/4/2007 4:00:00 AM -05:00 converted to 11/4/2007 1:00:00 AM Local
通用轉換方法
在下列範例中,會定義名為 ConvertFromDateTimeOffset 的方法,用它來將 DateTimeOffset 值轉換成 DateTime 值。根據其位移而定,它會判斷 DateTimeOffset 值是 UTC 時間、本地時間或其他時間,然後依此定義所傳回日期和時間值的 Kind 屬性。
Function ConvertFromDateTimeOffset(dateTime As DateTimeOffset) As Date
If dateTime.Offset.Equals(TimeSpan.Zero) Then
Return dateTime.UtcDateTime
ElseIf dateTime.Offset.Equals(TimeZoneInfo.Local.GetUtcOffset(dateTime.DateTime))
Return Date.SpecifyKind(dateTime.DateTime, DateTimeKind.Local)
Else
Return dateTime.DateTime
End If
End Function
static DateTime ConvertFromDateTimeOffset(DateTimeOffset dateTime)
{
if (dateTime.Offset.Equals(TimeSpan.Zero))
return dateTime.UtcDateTime;
else if (dateTime.Offset.Equals(TimeZoneInfo.Local.GetUtcOffset(dateTime.DateTime)))
return DateTime.SpecifyKind(dateTime.DateTime, DateTimeKind.Local);
else
return dateTime.DateTime;
}
下列範例會呼叫 ConvertFromDateTimeOffset 方法來轉換表示 UTC 時間、本地時間以及美國中央標準時區時間的 DateTimeOffset 值。
Dim timeComponent As Date = #06/19/2008 7:00AM#
Dim returnedDate As Date
' Convert UTC time
Dim utcTime As New DateTimeOffset(timeComponent, TimeSpan.Zero)
returnedDate = ConvertFromDateTimeOffset(utcTime)
Console.WriteLine("{0} converted to {1} {2}", _
utcTime, _
returnedDate, _
returnedDate.Kind.ToString())
' Convert local time
Dim localTime As New DateTimeOffset(timeComponent, _
TimeZoneInfo.Local.GetUtcOffset(timeComponent))
returnedDate = ConvertFromDateTimeOffset(localTime)
Console.WriteLine("{0} converted to {1} {2}", _
localTime, _
returnedDate, _
returnedDate.Kind.ToString())
' Convert Central Standard Time
Dim cstTime As New DateTimeOffset(timeComponent, _
TimeZoneInfo.FindSystemTimeZoneById("Central Standard Time").GetUtcOffset(timeComponent))
returnedDate = ConvertFromDateTimeOffset(cstTime)
Console.WriteLine("{0} converted to {1} {2}", _
cstTime, _
returnedDate, _
returnedDate.Kind.ToString())
' The example displays the following output to the console:
' 6/19/2008 7:00:00 AM +00:00 converted to 6/19/2008 7:00:00 AM Utc
' 6/19/2008 7:00:00 AM -07:00 converted to 6/19/2008 7:00:00 AM Local
' 6/19/2008 7:00:00 AM -05:00 converted to 6/19/2008 7:00:00 AM Unspecified
DateTime timeComponent = new DateTime(2008, 6, 19, 7, 0, 0);
DateTime returnedDate;
// Convert UTC time
DateTimeOffset utcTime = new DateTimeOffset(timeComponent, TimeSpan.Zero);
returnedDate = ConvertFromDateTimeOffset(utcTime);
Console.WriteLine("{0} converted to {1} {2}",
utcTime,
returnedDate,
returnedDate.Kind.ToString());
// Convert local time
DateTimeOffset localTime = new DateTimeOffset(timeComponent,
TimeZoneInfo.Local.GetUtcOffset(timeComponent));
returnedDate = ConvertFromDateTimeOffset(localTime);
Console.WriteLine("{0} converted to {1} {2}",
localTime,
returnedDate,
returnedDate.Kind.ToString());
// Convert Central Standard Time
DateTimeOffset cstTime = new DateTimeOffset(timeComponent,
TimeZoneInfo.FindSystemTimeZoneById("Central Standard Time").GetUtcOffset(timeComponent));
returnedDate = ConvertFromDateTimeOffset(cstTime);
Console.WriteLine("{0} converted to {1} {2}",
cstTime,
returnedDate,
returnedDate.Kind.ToString());
// The example displays the following output to the console:
// 6/19/2008 7:00:00 AM +00:00 converted to 6/19/2008 7:00:00 AM Utc
// 6/19/2008 7:00:00 AM -07:00 converted to 6/19/2008 7:00:00 AM Local
// 6/19/2008 7:00:00 AM -05:00 converted to 6/19/2008 7:00:00 AM Unspecified
請注意,此程式碼做了兩項假設,但根據應用程式以及其日期和時間值的來源,這些假設不一定會成立:
它假設位移為 Zero 的日期和時間值是代表 UTC。事實上,UTC 並不是特定時區的時間,而是相對於全球時區中已標準化的時間。時區也可以有 Zero 的位移。
它假設位移等於本地時區位移的日期和時間是代表本地時區。由於日期和時間值與其原始時區並不相關,因此假設不一定成立。日期和時間可能來自具有相同位移的另一個時區。