首页 > 解决方案 > 为什么 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

标签: c#.netdatetimetimezonedatetimeoffset

解决方案


首先,我不会调用你的函数GetUtcDateTime,因为它不是这样做的。它正在尝试获取DateTimeOffset特定时间的特定时区,因此将其称为GetDateTimeOffset.

您在代码中缺少的主要概念是DateTime具有.Kind设置DateTimeKind值的属性。您的代码中的几个地方都考虑了这种类型:

  • GetUtcOffset在确定偏移量之前将转换Utc或种类到提供的区域。Local

  • new DateTimeOffset(构造函数)如果类型和偏移量冲突,如果您提供偏移量,则会出错。

  • 当您将 a 分配DateTime给 a 时DateTimeOffset,隐式转换正在评估种类。

  • 当您从 调用.DateTimeDateTimeOffset,类型将始终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 DateTimetoDateTimeOffset将偏移量设置为00:00- 因为DateTime.UtcNowhas .Kind == DateTimeKind.Utc

在第 2 行,对.DateTime属性集的调用fromUtc.Kind == DateTimeKind.Unspecified。从本质上讲,你已经剥离了那种。

所以不是这个,而是DateTime.UtcNow直接传递给函数。这种类型将持续存在,并且一切都会起作用 - 现在Kind已识别并且转换正在函数内部进行。

综上所述,如果您的原始值都是DateTimeOffset(例如,DateTimeOffset.UtcNow),那么您根本不需要该功能。只需直接调用即可TimeZoneInfo.ConvertTimeDateTimeOffset


推荐阅读