下面的代码检查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
|