IsDayLightSavingTime方法针对相同的时区和相同的时间返回不同的值

以下代码检查DST中的特定时间,或者在正常的datetime和从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);


翻过高山走不出你
浏览 155回答 3
3回答

小唯快跑啊

Zohar基本上是正确的。关键点是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的切换发生在PST 02:00,因此两个值仍处于标准时间。那么,如何在没有黑客的情况下获得正确的答案呢?只需确保将输入值DateTimeKind.Utc转换为Windows文件时间之前的输入值即可。(DateTimeKind.Local也可以,但是这里不需要涉及当地时区)// First convert the DateTime values from their unspecified zone-specific times to UTCvar 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意味着你转换文件时,并输入DateTime与.Kind == DateTimeKind.Unspecified将被视为好像它是DateTimeKind.Utc。另一种方法是DateTime.ToFileTime将Unspecified种类视为Local。但是它们两者的处理方式Utc和Local种类都相同,并且都产生Windows文件时间,而Windows文件时间本质上是基于UTC的。除了上述方法之外,您也可以使用DateTimeOffset.ToFileTime。在转换为文件时间期间,将正确考虑偏移量。// construct a DateTimeOffset for each valuevar reminderStartTimeDto = new DateTimeOffset(reminderstarttime, tzInfo.GetUtcOffset(reminderstarttime));var referencetimeDto = new DateTimeOffset(referencetime, tzInfo.GetUtcOffset(referencetime));// then just convert them to file timesvar reminderStartTimeAsFileTime = reminderStartTimeDto.ToFileTime();var referenceTimeAsFileTime = referencetimeDto.ToFileTime();注意有没有ToFileTimeUtc在这里,因为没有Kind一个DateTimeOffset,所以只有一个将其转换方式。最后一件事。请注意,这DateTime.AddHours(10)并不能弥补DST的差距。因此,当您谈论太平洋标准时间上午8点时,由于弹簧向前的间隙,实际仅经过了9个小时。10个实际经过的时间为太平洋标准时间上午9点。如果在添加10小时之前保持值的DateTimeOffset类型不变,则可以轻松地对此进行更正。

万千封印

这段代码工作正常。之所以给出此响应,是因为夏令时的开始是因为夏令时于2018年3月11日美国和加拿大在凌晨02:00开始。

拉风的咖菲猫

更新尽管我仍然支持我的第一个版本说明,但是如果时间实际上是一天的节光时间,则转换为本地时间将给出错误的结果测试。我不确定为什么。我在rextester上玩过您的代码,试图为此提出解决方案。我发现的最好的解决方案非常麻烦-它涉及DateTime根据DateTime您所获得的实例创建一个新实例,结果是FromFileTimeUtc: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 = reminderstarttime.ToFileTimeUtc();var referenceTimeToUtc = referencetime.ToFileTimeUtc();var reminderStartTimeFromUtc = DateTime.FromFileTimeUtc(reminderStartTimeToUtc);var referencetimeFromUtc = DateTime.FromFileTimeUtc(referenceTimeToUtc);var isRemDSTFromFileTime = tzInfo.IsDaylightSavingTime(reminderStartTimeFromUtc);var isRefTimeDSTFromFileTime = tzInfo.IsDaylightSavingTime(referencetimeFromUtc);var referenceTimeFromFileTimeUnspecified = new DateTime(referencetimeFromUtc.Ticks);var isReferenceTimeFromFileTimeUnspecifiedDTS =  tzInfo.IsDaylightSavingTime(referenceTimeFromFileTimeUnspecified);Console.WriteLine("isRemDstWithNormal: " + isRemDstWithNormal +                  "\nisRefDstWithNormal: " + isRefDstWithNormal +                  "\nisRemDSTFromFileTime " + isRemDSTFromFileTime +                  "\nisRefTimeDSTFromFileTime: " + isRefTimeDSTFromFileTime +                 "\nisReferenceTimeFromFileTimeUnspecifiedDTS: "+ isReferenceTimeFromFileTimeUnspecifiedDTS);我承认这可能是解决方法,而不是解决方案,但我想我在这个问题上花了更多时间,所以我已经负担得起了。也许对日期时间,文件时间和时区有更多经验的人可以对此有所了解。第一版问题是您referencetime的Kind财产是DateTimeKind.Unspecified。如果DateTimeKind.Local在的构造函数中指定reminderstarttime,则会得到准确的结果。请参见方法文档中的“备注”部分DateTime.ToFileTimeUtc:ToFileTimeUtc方法使用Kind属性来确定当前DateTime对象是本地时间,UTC时间还是被视为UTC时间的未指定类型的时间。如果是本地时间,它将在转换为Windows文件时间之前将时间转换为UTC。(强调我的)这是我的测试代码:var tzInfo = TimeZoneInfo.FindSystemTimeZoneById("Pacific Standard Time");// This is the only change, except replacing the space with \n in the Console.WriteLine://var reminderstarttime = new DateTime(2018, 3, 10, 22, 0, 0);var reminderstarttime = new DateTime(2018, 3, 10, 22, 0, 0, DateTimeKind.Local);var referencetime = reminderstarttime.AddHours(10);  // ReferencedTime is in DST;var isRemDstWithNormal = tzInfo.IsDaylightSavingTime(reminderstarttime);var isRefDstWithNormal = tzInfo.IsDaylightSavingTime(referencetime);var reminderStartTimeToUtc = reminderstarttime.ToFileTimeUtc();var referenceTimeToUtc = referencetime.ToFileTimeUtc();var reminderStartTimeFromUtc = DateTime.FromFileTimeUtc(reminderStartTimeToUtc);var referencetimeFromUtc = DateTime.FromFileTimeUtc(referenceTimeToUtc);var isRemDSTFromFileTime = tzInfo.IsDaylightSavingTime(reminderStartTimeFromUtc);var isRefTimeDSTFromFileTime = tzInfo.IsDaylightSavingTime(referencetimeFromUtc);Console.WriteLine("isRemDstWithNormal: " + isRemDstWithNormal +                  "\nisRefDstWithNormal: " + isRefDstWithNormal +                  "\nisRemDSTFromFileTime " + isRemDSTFromFileTime +                  "\nisRefTimeDSTFromFileTime: " + isRefTimeDSTFromFileTime);结果:isRemDstWithNormal: FalseisRefDstWithNormal: FalseisRemDSTFromFileTime FalseisRefTimeDSTFromFileTime: False
打开App,查看更多内容
随时随地看视频慕课网APP