分享

c# – IsDayLightSavingTime方法为同一时区和同一时间返回不同的值

 印度阿三17 2019-07-01

下面的代码检查DST中的特定时间或不返回与正常日期时间相同的时间的不同值以及从filetime获取的值:

var tzInfo = TimeZoneInfo.FindSystemTimeZoneById("Pacific Standard Time");
var reminderstarttime = new DateTime(2018, 3, 10, 22, 0, 0);
var referencetime = reminderstarttime.AddHours(10);  // ReferencedTime is in DST;

var isRemDstWithNormal = tzInfo.IsDaylightSavingTime(reminderstarttime);
var isRefDstWithNormal = tzInfo.IsDaylightSavingTime(referencetime);

var reminderStartTimeToUtc = (ulong)reminderstarttime.ToFileTimeUtc();
var referenceTimeToUtc = (ulong)referencetime.ToFileTimeUtc();

var reminderStartTimeFromUtc = DateTime.FromFileTimeUtc((long)reminderStartTimeToUtc);
var referencetimeFromUtc = DateTime.FromFileTimeUtc((long)referenceTimeToUtc);

var isRemDSTFromFileTime = tzInfo.IsDaylightSavingTime(reminderStartTimeFromUtc);
var isRefTimeDSTFromFileTime = tzInfo.IsDaylightSavingTime(referencetimeFromUtc);

Console.WriteLine("isRemDstWithNormal: "   isRemDstWithNormal   
                 " isRefDstWithNormal: "   isRefDstWithNormal   
                 " isRemDSTFromFileTime "   isRemDSTFromFileTime   
                 " isRefTimeDSTFromFileTime: "   isRefTimeDSTFromFileTime);

解决方法:

佐哈尔大概是正确的.关键点是DateTime.ToFileTimeUtc与许多处理DateTime的方法一样,取决于与值关联的Kind.当传递DateTimeKind.Unspecified时,此特定方法假定输入已经是UTC.但是,在您的代码中,您创建的这些值就像它们所给定的时区一样.

让我们归咎于罪魁祸首:

var reminderStartTimeToUtc = (ulong)reminderstarttime.ToFileTimeUtc();
var referenceTimeToUtc = (ulong)referencetime.ToFileTimeUtc();

由于reminderstarttime和referencetime都具有Kind == DateTimeKind.Unspecified,因此它们的结果文件时间值不正确.特别:

reminderStartTimeToUtc:  131651928000000000
             we wanted:  131652216000000000
            difference:       -288000000000  = -8 hours

    referenceTimeToUtc:  131652288000000000
             we wanted:  131652540000000000
            difference:       -252000000000  = -7 hours

如您所见,它们的值与每个相应日期的UTC差异有所不同.

使用DateTime.FromFileTimeUtc在代码中将它们转换回来会返回具有DateTimeKind.Utc的值,这会抛出后续的DST检查:

reminderStartTimeFromUtc:  2018-03-10 22:00:00 UTC
  which is equivalent to:  2018-03-10 14:00:00 PST (UTC-8)
               we wanted:  2018-03-10 22:00:00 PST (UTC-8)

    referencetimeFromUtc:  2018-03-11 08:00:00 UTC
  which is equivalent to:  2018-03-11 00:00:00 PST (UTC-8)
               we wanted:  2018-03-11 08:00:00 PDT (UTC-8)

请注意,从PST到PDT的切换发生在太平洋标准时间02:00,因此两个值仍处于标准时间.

那么我们如何在没有黑客的情况下得到正确的结果呢?在转换为Windows文件时间之前,只需确保我们的输入值是DateTimeKind.Utc. (DateTimeKind.Local也可以,但是这里不需要涉及本地时区)

// First convert the DateTime values from their unspecified zone-specific times to UTC
var reminderStartTimeUtc = TimeZoneInfo.ConvertTimeToUtc(reminderstarttime, tzInfo);
var referenceTimeUtc = TimeZoneInfo.ConvertTimeToUtc(referencetime, tzInfo);

// Then convert THOSE values to file-times.
var reminderStartTimeToUtc = (ulong)reminderStartTimeUtc.ToFileTimeUtc();
var referenceTimeToUtc = (ulong)referenceTimeUtc.ToFileTimeUtc();

其余代码将按原样正确跟随,您将获得预期的结果.

请注意,这些方法的措辞有些令人困惑. DateTime.ToFileTimeUtc表示您正在转换为文件时间,并且具有.Kind == DateTimeKind.Unspecified的输入DateTime将被视为DateTimeKind.Utc.另一种方法DateTime.ToFileTime将Unspecified种类视为Local.但他们都同样对待Utc和Local类型,它们都产生一个Windows文件时间,这本身就是基于UTC的.

作为上述方法的替代方法,您可以使用DateTimeOffset.ToFileTime.在转换为文件时间期间,将正确考虑偏移量.

// construct a DateTimeOffset for each value
var reminderStartTimeDto = new DateTimeOffset(reminderstarttime, tzInfo.GetUtcOffset(reminderstarttime));
var referencetimeDto = new DateTimeOffset(referencetime, tzInfo.GetUtcOffset(referencetime));

// then just convert them to file times
var reminderStartTimeAsFileTime = reminderStartTimeDto.ToFileTime();
var referenceTimeAsFileTime = referencetimeDto.ToFileTime();

注意这里没有ToFileTimeUtc,因为DateTimeOffset上没有Kind,所以只有一种方法可以转换它.

最后一件事.请注意,DateTime.AddHours(10)不符合DST差距.因此,当你在谈论上午8点的PDT时,由于春季前进的差距,实际上只有9个小时.实际经过的10小时是太平洋夏令时上午9点.如果在添加10小时之前保留DateTimeOffset类型的值,则可以轻松纠正此问题.

来源:https://www./content-1-287301.html

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多