c# - 为什么 UtcDateTime 函数没有将偏移量添加到 UTC 日期?
问题描述
对于瞬时 DateTime 跟踪,我使用的是DateTimeOffset
数据类型。以下函数将用户对应的 TimeZone ID 偏移量添加到 UTC DateTime 属性中DateTimeOffset
根据文档,UtcDateTime
将在DateTimeOffset
. 以下代码没有。为什么没有发生转换?
添加 TimeSpan 偏移量的函数,
public static DateTimeOffset GetUtcDateTime (DateTime sourceDateTime, string timeZoneId) {
TimeZoneInfo timeZone = TimeZoneInfo.FindSystemTimeZoneById (timeZoneId);
TimeSpan offset = timeZone.GetUtcOffset (sourceDateTime);
DateTimeOffset utcTime = new DateTimeOffset (sourceDateTime, offset);
return utcTime;
}
在这里我试图转换,
DateTimeOffset utcDate = (DateTime.UtcNow);
DateTime fromUtc = utcDate.DateTime;
DateTimeOffset UtcDate = StaticHandlers.GetUtcDateTime (fromUtc, "America/Los_Angeles");
Console.WriteLine ("UTC now is {0} and UTC Date LA is {1} and UtcDateTime LA is {2}", utcDate, UtcDate, utcDate.UtcDateTime);
输出是,
UTC 现在是 5/8/18 6:43:37 AM +00:00 和 UTC Date LA 是 5/8/18 6:43:37 AM -07:00 UtcDateTime LA 是 5/8/18 6:43上午 37 点
更新,
我想保留 UTC 和用户偏移量以进行跟踪。DST 在这种情况下很重要。下面的例子显示了我在说什么。
DateTime currentDateTime = DateTime.Now;
DateTime beforeDST_LA = new DateTime (2018, 3, 11, 0, 0, 0);
DateTime afterDST_LA = new DateTime (2018, 3, 12, 0, 0, 0);
TimeSpan offsetCurrent = tzi.GetUtcOffset (currentDateTime);
TimeSpan offsetBeforeDST = tzi.GetUtcOffset (beforeDST_LA);
TimeSpan offsetAfterDST = tzi.GetUtcOffset (afterDST_LA);
Console.WriteLine ("Current offset is {0} before DST is {1} and After DST is {2}", offsetCurrent, offsetBeforeDST, offsetAfterDST);
当前偏移量在 DST 为 -08:00:00 之前为 -07:00:00,DST 之后为 -07:00:00
解决方案
首先,我不会调用你的函数GetUtcDateTime
,因为它不是这样做的。它正在尝试获取DateTimeOffset
特定时间的特定时区,因此将其称为GetDateTimeOffset
.
您在代码中缺少的主要概念是DateTime
具有.Kind
设置DateTimeKind
值的属性。您的代码中的几个地方都考虑了这种类型:
GetUtcOffset
在确定偏移量之前将转换Utc
或种类到提供的区域。Local
new DateTimeOffset
(构造函数)如果类型和偏移量冲突,如果您提供偏移量,则会出错。当您将 a 分配
DateTime
给 a 时DateTimeOffset
,隐式转换正在评估种类。当您从 调用
.DateTime
时DateTimeOffset
,类型将始终为Unspecified
- 无论偏移量如何。
如果您将所有这些都考虑在内,您会意识到在致电之前您需要自己检查一下GetUtcOffset
。如果不是 Unspecified
,那么您需要在获取偏移量之前将其转换为指定的时区。
public static DateTimeOffset GetDateTimeOffset(DateTime sourceDateTime, string timeZoneId)
{
TimeZoneInfo timeZone = TimeZoneInfo.FindSystemTimeZoneById(timeZoneId);
// here, is where you need to convert
if (sourceDateTime.Kind != DateTimeKind.Unspecified)
sourceDateTime = TimeZoneInfo.ConvertTime(sourceDateTime, timeZone);
TimeSpan offset = timeZone.GetUtcOffset(sourceDateTime);
return new DateTimeOffset(sourceDateTime, offset);
}
现在已经处理好了,转向下一组问题,这就是你所说的。
DateTimeOffset utcDate = (DateTime.UtcNow);
DateTime fromUtc = utcDate.DateTime;
在第 1 行,隐式转换 from DateTime
toDateTimeOffset
将偏移量设置为00:00
- 因为DateTime.UtcNow
has .Kind == DateTimeKind.Utc
。
在第 2 行,对.DateTime
属性集的调用fromUtc.Kind == DateTimeKind.Unspecified
。从本质上讲,你已经剥离了那种。
所以不是这个,而是DateTime.UtcNow
直接传递给函数。这种类型将持续存在,并且一切都会起作用 - 现在Kind
已识别并且转换正在函数内部进行。
综上所述,如果您的原始值都是DateTimeOffset
(例如,DateTimeOffset.UtcNow
),那么您根本不需要该功能。只需直接调用即可TimeZoneInfo.ConvertTime
。DateTimeOffset