小林寺丸比较日期和时间

2022-02-15 00:51:13

我们刚刚在@userlist Slack中与@leoeuclids和@UIBreaken就比较日期和时间进行了一个长时间的一小时讨论…🙈 有人对此有意见吗?🤪 照片。啁啾com/G0muPbOhS9

-Benedikt Deicke(@benediktdeicke)2022年2月11日

在一个松弛线程中,至少有100个回复是询问关于编程中时间和日期的边缘案例的现行速率。仅供将来参考。

由于Twitter的嵌入有点咄咄逼人,下面是推文中的图片:

推特上的回复立刻变得混乱。答案包括“是/是/否”、“否/否”(这是我最初的回答,但从那时起我也混乱地改变了主意)、“否/否/是”、“日期最糟糕”和“你试过使用🍺? 也许很多很多🍻 然后就好像假装没发生过一样?"

作为一个写了太多关于日期、时间和边缘案例的人,我发现这次讨论令人兴奋,完全是浪费时间,我真的迫不及待地想再深入探讨一下。

如果你发现自己处于这种状态,很明显出了问题。我这样说是不加评判的,因为除非你在一个没有用户的洁净室里开发一个产品,而且代码的使用时间不超过一个小时,否则你会遇到数据不一致的问题,而且不一致的日期戳和时间戳存储是非常常见的。就在本周,我遇到了一个类似的问题,我继承了大量不一致的邮戳和时间戳。

这些是来自用户界面的输入和来自数据库的数据。因此,这也很大程度上取决于人们期望发生什么(技术和非技术)。

-Benedikt Deicke(@benediktdeicke)2022年2月12日

更重要的是,原始问题中还有一个被遗漏的问题,UTC的哪些精明读者对每个人来说都足够了,对吗?可能已经注意到了:没有时区数据!对于日期值来说,这是可以理解的,因为时区通常是不需要的(这和这个领域的大多数事情一样,并不总是正确的),但是,需要时间值来确保有效的比较(可以想象,同一“天”的00:00:00和12:00:00的比较可能会中断几天,具体取决于时区)。当然,如果你想正确地计算历史夏令时,你需要存储的不仅仅是偏移量。

所以这是一个没有双赢的解决方案。我可以为推特回复中的几乎每一个答案(尤其是关于啤酒的答案)提供有效的论据。之所以特别令人沮丧,是因为我们在日常生活中总是做出这些仓促的决定,而且非常容易。当我告诉你们今天中午和我共进午餐时,很可能我们谈论的是彼此在同一个地方、同一时区、同一天,所以我们不必花太多时间思考这个问题。

问题是日期和时间是彼此的超集。这有点自相矛盾。但让我们进一步看一下:

一个日期可以被认为是一个时间的超集,因为所有的小时、分、秒自然都属于某一天。

如果你认为时间是一个特定时间的扩展,那么时间可以被认为是一个日期的超集。从正午到正午跨越两个不同的日子。或者,只要一天,如果是24小时制而不是日历日。就连我对悖论的解释也有悖论。

这两种定义都是错误的,也都是正确的,这就是为什么你可以在这里为这么多答案辩护。这实际上取决于你的价值。

这就是为什么我觉得这些东西如此迷人的关键。众所周知,我们程序员倾向于以真正的二元意义来看待世界:代码运行或不运行。测试通过或不通过。记录有效或无效。这是一种非常有用的看待世界的方式……直到它不存在。不过,通常它不会直接烘焙到系统中。

有些例子根本不存在正确的答案。我最喜欢的例子——是的,我也最喜欢时间问题的例子——是在依赖于位置的夏令时边界上重复发生的事件。

假设您与开发团队的其他成员每周在太平洋时间上午10点举行一次定期日历活动。就像一家真正的远程第一公司一样,你的公司分布广泛,而不仅仅是一个主要团队在一个城市,一个兰多在“远程”工作。这很好,但它也增加了一个城市、地区或国家与其他城市、地区或国家(如果它们甚至有一个夏令时政策的话)有不同夏令时政策的可能性。

几个月来,你一直在打上午10点的电话,然后住在西弗吉尼亚州的维吉尼亚在3月份开始夏令时。所以现在上午10点的太平洋会议时间,也就是她下午1点的时间,对她来说仍然是下午1点,因为太平洋时间也总是遵循DST(加拿大育空地区除外,该地区在2020年决定停止遵循DST)。但你的队友布鲁克林住在凤凰城,她没有夏令时,因为她住在亚利桑那州,那里不遵循夏令时(但别忘了,亚利桑那州北部的纳瓦霍民族也遵循DST,所以一定要记住这一点)。

那么:布鲁克林是否保持正常的上午11点会议时间,或者她是否继续与布鲁克林会面,必须在中午开始开会?她的生活没有任何改变。一次会议突然在她的午餐休息时间结束,而之前没有,这是很奇怪的。

答案是:没有答案。我们只是在弥补。这就是答案。谷歌在其开发者API文档中有一个关于日历的书面文件,广泛讨论了重复事件如何与受邀参与者互动。一个方面:

这是唯一合理的方法。他们认为,最初活动的创造者获胜,其影响也渗透到与会者身上。

*从“RRULE”生成起始日期时间值(实例)时,必须使用“DTSTART”和“TZOFFSETFROM”属性。

(RFC 5545也是一本很棒的、令人兴奋的书。我还以为我在读一本小丑的爱情小说,书中生动地描述了所有的规则和排列。)

所以:回到手头的原始话题……我认为这是一个我们可以随意做出决定的案例。没有“对”或“错”的答案。

我很好奇其他人是如何广泛地思考这个问题的,所以我进一步研究了一下。

Ruby有一篇关于莎士比亚的可爱论文,他们讨论了使用时间与日期时间的关系,这涉及到了其中一些问题——值得阅读整个章节,但这一部分在这里最相关:

那么什么时候应该在Ruby中使用DateTime,什么时候应该使用Time呢?几乎可以肯定的是,你会想使用时间,因为你的应用程序可能正在处理当前的日期和时间。然而,如果你需要在历史背景下处理日期和时间,你会希望使用DateTime来避免犯与UNESCO相同的错误。如果你还需要处理时区问题,那么祝你好运——请记住,你可能会处理当地的太阳时,因为直到19世纪,铁路的引入才需要标准时间,最终需要时区。

NET也有一种“哦,上帝,尽量避免任何这类事情”的理念:

为了确定t1和t2之间的关系,比较方法会比较t1和t2的滴答声特性,但会忽略它们的种类特性。[Ed.注:这里的Kind实际上是与时区相关的数据。]在比较DateTime对象之前,请确保这些对象代表同一时区中的时间。

如果日期/时间间隔超过14小时,该方法仍然有效,但如果间隔小于14小时,则结果被视为不确定。

由于第二个参数决定精度,而不仅仅是要检查的单个值,因此使用day将检查年、月和日。[Ed.注:这基本上意味着你必须选择要决定的精度——对于原始推文,你可以选择几天或几秒钟。]

如果两个时刻的时区不同,则将使用第一个时刻的时区进行比较。

这篇文章基本上是一种冗长的方式,重申人类在日期和时间上创造了一些非常奇怪的场景。Raphael Schaad是神奇的Cron日历的创始人,他有一个长期运行的思路,关于日历的错误假设,坦率地说,并不总是有合乎逻辑的解决方案。这都是一系列的权衡。

这就是为什么我发现原来的推特如此有趣。我们都遇到过数据不一致的情况,或者第三方为我们错误地屏蔽了数据,或者我们继承了在错误假设下保存的数据(尽管当时可能是正确的)。思考的过程可能会导致100条线索。或者一篇关于日期和时间的太长太详细的周六早报。

开玩笑。我知道你们有些人已经到星期天了。你们中的一些人几年后会读到它!不过,我敢肯定一周前没人读过这篇文章。如果你写了,请几天前提醒我,从现在起,我需要在几个小时前写这篇文章。