在 DateTime 与 DateTimeOffset 之间进行转换
虽然与 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 值。 下面的示例对此进行了演示,该示例使用美国 它将返回 9/1/2007 3:32:07 AM -07:00。
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 属性不同:
如果 Offset 属性值不等于 TimeSpan.Zero,它会将时间转换成 UTC。
![]() |
---|
如果您的应用程序要求转换的 DateTime 值明确地标识单个时间点,那么您应该考虑使用 DateTimeOffset.UtcDateTime 属性来处理所有从 DateTimeOffset 到 DateTime 的转换。 |
下面的代码使用 UtcDateTime 属性将其偏移量等于 TimeSpan.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
请注意,此代码做出了两个假设,根据应用程序及其日期和时间值的来源,这两个假设并非始终有效:
它假设其偏移量为 TimeSpan.Zero 的日期和时间值表示 UTC。 实际上,UTC 不是某个特定的时区中的时间,而是世界上的时区中的时间相对它进行标准化的时间。 时区的偏移量还可以是 Zero。
它假设其偏移量等于本地时区偏移量的日期和时间表示本地时区。 由于日期和时间值与其原始时区解除了关联,情况不一定是这样的;日期和时间可能源自偏移量相同的另一个时区。