我刚刚注意到日期时间比较的一个可笑的缺陷。
DateTime d = DateTime.Now;
DateTime dUtc = d.ToUniversalTime();
d == dUtc; // false
d.Equals(dUtc); //false
DateTime.Compare(d, dUtc) == 0; // false
如果一个是DateTimeKind.Local,另一个是DateTimeKind.UTC,则对DateTimes执行的所有比较操作似乎都无法执行任何类型的智能转换。除了始终将比较中涉及的两个操作都转换为utc时间之外,这是可靠地比较DateTimes的更好方法吗?
2条答案
按热度按时间dsekswqp1#
当你调用
.Equal
或.Compare
时,内部比较的是.InternalTicks
,它是一个没有前两位的ulong
,这个字段是 * 不相等的 *,因为它被调整了几个小时来表示世界时:当你调用ToUniversalTime()
时,它会用当前系统的本地时区设置的偏移量来调整时间。你应该这样看:DateTime对象表示一个未命名时区中的 time,但不是世界时加时区。时区可以是Local(系统的时区)或UTC。您可能认为这是缺少DateTime类,但历史上它一直被实现为“自1970年以来的滴答数”,并且不包含时区信息。
当 * 转换 * 到另一个时区时,时间是--而且应该是--调整的。这可能就是为什么微软选择使用 * 方法 * 而不是属性,以强调转换到UTC时采取的操作。
最初我在这里写的是比较结构体,
System.DateTime.Kind
的标志是不同的,这是不正确的:不同的是滴答声的数量:为了安全地比较两个日期,您可以将它们转换为同一种日期。如果在比较之前将任何日期转换为世界时间,您将得到所需的结果:
转换为UTC时间而不更改本地时间
除了将
DateTimeKind
* 转换 * 为UTC(并且在此过程中保持时间不变,但嘀嗒数不同),您还可以 * 覆盖 *DateTimeKind
并将其设置为UTC(这会更改时间,因为它现在是UTC格式,但它比较起来是相等的,因为嘀嗒数相等)。我猜
DateTime
是一种罕见的类型,它可以按位不相等,但比较起来相等,或者可以按位相等(时间部分),但比较起来不相等。.NET 6中的更改
在.NET 6.0中,我们现在有了
TimeOnly
和DateOnly
,你可以用它们来存储 “仅仅是一天中的时间”,of “仅仅是一年中的日期”,把它们组合在一个结构体中,你就得到了一个没有原始DateTime
的历史麻烦的Date & Time结构体。备选方案
在. NET中,很难正确地使用
DateTime
、TimeZoneInfo
、闰秒、日历、时区转换、持续时间等。我个人更喜欢Jon Skeet的NodaTime
,它以一种有意义、明确的方式将控制权交还给程序员。This insightful post by Jon Skeet explains非常深入地介绍了程序员在尝试规避所有日期时间问题时可能面临的麻烦,而只是将所有内容存储在UTC中。
来自源的背景信息
如果你检查the
DateTime
struct in the .NET source,你会发现一个注解,解释了DateTime
最初(在.NET 1.0中)只是滴答数,但后来他们增加了存储它是通用时间还是本地时间的能力。这是来源中的注解:
ss2ws0br2#
为了解决这个问题,我创建了自己的DateTime对象(我们称之为SmartDateTime),其中包含DateTime和TimeZone。我覆盖了所有操作符,如==和Compare,并在使用原始DateTime操作符进行比较之前将其转换为UTC。