在 DateTime 与 DateTimeOffset 之间进行转换
更新:2007 年 11 月
虽然与 DateTime 结构相比 DateTimeOffset 结构提供了更高程度的时区识别能力,但在方法调用中 DateTime 参数更常用。因此,将 DateTimeOffset 值转换为 DateTime 值(反之亦然)的能力就尤为重要。本主题演示如何在保留尽可能多的时区信息的情况下执行这些转换。
![]() |
---|
表示时区中的时间时,DateTime 和 DateTimeOffset 类型都有一些限制。通过其 Kind 属性,DateTime 只能反映协调世界时 (UTC) 和系统的本地时区。DateTimeOffset 反映时间相对于 UTC 的偏移量,但它不反映该偏移量所属的实际时区。有关时间值和对时区的支持的详细信息,请参见在 DateTime、DateTimeOffset 和 TimeZoneInfo 之间进行选择。 |
从 DateTime 到 DateTimeOffset 的转换
DateTimeOffset 结构提供了两种等效的方式来执行从 DateTime 到 DateTimeOffset 的转换,这两种方式适用于大多数转换:
DateTimeOffset 构造函数,它根据 DateTime 值创建新的 DateTimeOffset 对象。
隐式转换运算符,它允许您为 DateTimeOffset 对象分配一个 DateTime 值。
对于 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
此构造函数重载的第二个参数,应该通过调用该时间对应的时区的 TimeZoneInfo.GetUtcOffset(DateTime) 方法检索一个表示该时间相对于 UTC 的偏移量的 TimeSpan 对象。该方法的单个参数是表示要转换的日期和时间的 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 方法转换 DateTimeOffset 值,该值表示 UTC 时间、本地时间,以及美国中部标准时区时间。
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。
它假设其偏移量等于本地时区偏移量的日期和时间表示本地时区。由于日期和时间值与其原始时区解除了关联,情况不一定是这样的;日期和时间可能源自偏移量相同的另一个时区。