简体   繁体   English

为什么UtcDateTime函数不将偏移量添加到UTC日期?

[英]Why UtcDateTime function is not adding the offset to the UTC date?

For instantaneous DateTime tracking, I am using a DateTimeOffset datatype. 对于瞬时DateTime跟踪,我使用的是DateTimeOffset数据类型。 The following function adds the user corresponding TimeZone ID offset to the UTC DateTime property of DateTimeOffset 下面的函数将用户对应的时区ID偏移到的日期时间UTC属性DateTimeOffset

According to the documentation , UtcDateTime will perform both a time zone conversion and a type conversion on a DateTimeOffset . 根据文档UtcDateTime将在DateTimeOffset上执行时区转换和类型转换。 The following code does not though. 以下代码没有。 Why is the conversion not taking place? 为什么没有进行转换?

Function to add TimeSpan offset, 用于添加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;
 }

and here where I am trying to convert, 在这里,我试图转变,

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);

the output is, 输出是

UTC now is 5/8/18 6:43:37 AM +00:00 and and UTC Date LA is 5/8/18 6:43:37 AM -07:00 UtcDateTime LA is 5/8/18 6:43:37 AM UTC现在是5/8/18 6:43:37 AM +00:00,并且UTC日期LA是5/8/18 6:43:37 AM -07:00 UtcDateTime LA是5/8/18 6:43 :37上午

update, 更新,

I want to preserve both UTC and the user offset for tracking purposes. 我想同时保留UTC和用户偏移量以进行跟踪。 DST matters in this context. 在这种情况下,DST很重要。 The example below shows what I am talking about. 下面的示例显示了我在说什么。

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);

Current offset is -07:00:00 before DST is -08:00:00 and After DST is -07:00:00 当前偏移是DST -08:00:00之前和DST之后-07:00:00 -07:00:00

First, I would not call your function GetUtcDateTime , because that's not what it does. 首先,我不会调用您的函数GetUtcDateTime ,因为那不是它的功能。 It is trying to get a DateTimeOffset for a specific time zone for a specific time, so call it something like GetDateTimeOffset . 它正在尝试获取特定时区特定时间的DateTimeOffset ,因此将其命名为GetDateTimeOffset

The main concept you're missing in your code is that DateTime has .Kind property, which sets a DateTimeKind value. 您的代码中缺少的主要概念是DateTime具有.Kind属性,该属性设置了DateTimeKind值。 The kind is taken into consideration by several places in your code: 您的代码中的多个地方都考虑到了这种类型:

  • GetUtcOffset will convert Utc or Local kinds to the zone provided before determining the offset. 在确定偏移量之前, GetUtcOffset会将UtcLocal种类转换为提供的区域。

  • new DateTimeOffset (the constructor) will error if the kind and the offset conflict, if you provide an offset. 如果提供偏移量,则种类和偏移量冲突时, new DateTimeOffset (构造函数)将出错。

  • When you assign a DateTime to a DateTimeOffset , the implicit conversion is evaluating the kind. 当您将DateTime分配给DateTimeOffset ,隐式转换将评估类型。

  • When you call .DateTime from the DateTimeOffset , the kind will always be Unspecified - regardless of the offset. 当您从DateTimeOffset调用.DateTime ,该类型将始终Unspecified -与偏移量无关。

If you take all of this into account, you'll realize you need to check the kind yourself before calling GetUtcOffset . 如果考虑到所有这些,您将意识到需要在调用GetUtcOffset之前先检查类型。 If it's not Unspecified then you'll need to convert it to the specified time zone before getting the offset. 如果 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);
}

Now that this is handled, turn to the next set of problems, which is where you call it. 既然已经解决了,请转到下一个问题集,即您所称的地方。

DateTimeOffset utcDate = (DateTime.UtcNow);
DateTime fromUtc = utcDate.DateTime;

In line 1, the implicit cast from DateTime to DateTimeOffset sets the offset to 00:00 - because DateTime.UtcNow has .Kind == DateTimeKind.Utc . 在第1行中,从DateTimeDateTimeOffset的隐式.Kind == DateTimeKind.Utc将偏移量设置为00:00 : .Kind == DateTimeKind.Utc因为DateTime.UtcNow具有.Kind == DateTimeKind.Utc

In line 2, the call to the .DateTime property sets fromUtc.Kind == DateTimeKind.Unspecified . 在第2行中,对.DateTime属性的调用设置为fromUtc.Kind == DateTimeKind.Unspecified Essentially, you've stripped away the kind. 本质上,您已经剥离了那种。

So instead of this, just pass DateTime.UtcNow directly into the function. 因此, DateTime.UtcNow替代,只需将DateTime.UtcNow直接传递给该函数。 The kind will persist, and it will all work - now that the Kind is recognized and the conversion is happening inside the function. 种类将持续存在,并且将全部正常工作-现在可以识别Kind ,并且函数内将发生转换。

All that said, if your original values are all DateTimeOffset (example, DateTimeOffset.UtcNow ) then you don't need that function at all. 话虽如此,如果您的原始值全部是DateTimeOffset (例如DateTimeOffset.UtcNow ),那么您根本不需要该函数。 Just call TimeZoneInfo.ConvertTime with the DateTimeOffset directly. 只需直接使用DateTimeOffset调用TimeZoneInfo.ConvertTime

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM