是否有包含/排除时间间隔结束的标准? java.time & Half-Open关于 java.time

2022-08-31 17:34:42

我想知道是否有标准或“正常”的方法来解释时间间隔数据端点,相对于定义端点的值的包容性/排他性。但请注意,我问的是标准(或最常见的)惯例是什么(如果有的话),而不是关于您个人偏好的论文。如果您真的想提供论文,请将其附加到某人已发布的标准或有关此事的标准文本的参考中。开放标准(我不必付费阅读)是首选,除非它们在:)存在根本缺陷。

当然,从A到B的时间间隔有4种可能性:

  1. (A, B) - 两端都是排他性的。
  2. [A, B] - 两端都是包容性的。
  3. [A, B) - 开始是包容性的,结束是排他性的
  4. (A, B] - 开始是排他性的,结束是包容的

这些中的每一个都有不同的特征(正如我所看到的,请随时指出更多)

[A, B] 约定将具有看似不方便的属性,即 B 包含在内在 [A, B] 和 [B, C] 中。例如,如果 B 表示午夜边界,并且您试图确定它落在哪一天,则这尤其不方便。此外,这意味着计算间隔的持续时间略有刺激性,因为[A,B]其中A = B的长度应为1,因此[A,B]的持续时间为(B - A)+ 1

类似地,(A,B)公约的难度是B既不属于(A,B)也不属于(B,C)......继续用日边界进行类比,午夜将不是任何一天的一部分。这在逻辑上也很不方便,因为[A, B]其中A = B是持续时间小于零的非意义区间,但反转A和B并不能使其成为有效的区间

所以我想我想要[A,B)或(A,B],我不知道如何在它们之间做出决定。

因此,如果有人有标准文档的链接,请参考标准文本或类似文本,以澄清约定,这将是伟大的。或者,如果您可以链接各种或多或少完全不同意的标准文档和/或参考文献,那么我可以选择一个似乎对CMA具有足够权限并完成:)。

最后,我将使用Java,因此我特别容易受到在Java中运行良好的答案的影响。


答案 1

在一般情况下,(包括开始,排他性结束)有很多事情要做,我看不出任何理由为什么时间间隔不会如此。[A, B)

Djikstra写了一篇关于它的好文章 为什么编号应该从零开始 - 尽管名称如此 - 主要涉及这一点。

优点的简短总结:

  • end - start等于列表中的项目数
  • 前一个区间的上限是下一个区间的下限
  • 允许索引从 0 开始的区间,并带有无符号数字 [1]

就个人而言,第二点对于许多问题非常有用;考虑一个非常标准的递归函数(在伪python中):

def foo(start, end):
    if end - start == 1:
        # base case
    else:
        middle = start + (end - start) / 2
        foo(start, middle)
        foo(middle, end)

用包含上限写同样的东西会引入很多容易被一个错误忽略的错误。

[1] 与 - 从 0 开始的区间比以 结尾的区间更常见。请注意,这也与另一个问题有关:使用两个非包含边界意味着我们可以表示其长度不能以相同大小表示的序列。(A, B]MAX_VAL


答案 2

java.time & Half-Open

取代麻烦的旧日期时间类的java.time类以及Joda-Time项目使用半开放方法定义了时间跨度[),其中开头是包容性的,而结尾是排他性的

对于小数秒的日期时间,这消除了尝试捕获最后一刻的问题。必须解决无限可整除的最后一秒,但各种系统使用各种粒度,例如毫秒,微秒,纳秒或其他东西。例如,对于半开,一天从一天的第一个时刻开始,一直持续到(但不包括)第二天的第一个时刻。问题解决了,无需与一天中的最后一刻及其小数秒摔跤。

我已经看到了在所有日期时间处理代码中始终如一地使用此方法的好处。例如,从星期一开始的一周一会一直持续到下一个星期一,但不包括下一个星期一。一个月从1日开始,一直持续到下个月的第一天,但不包括下个月的第一天,因此忽略了确定该月最后一天(包括2月28/29闰年)数字的挑战。

一致使用Half-Open [)的另一个好处是,每次我必须检测、破译和验证一段代码的时间跨度方法时,都能减轻认知负荷。在我自己的编程中,我只需在顶部的评论中浏览一下半开的提及,我就会立即知道如何阅读该代码。

一致使用半開的結果是減少了我的代碼中出現錯誤的機會,因為我的思維和寫作風格是一致的,沒有機會混淆包容性 - 獨佔性。

顺便说一句,请注意,半开 [) 意味着避免 SQL 连词,因为它始终是完全闭合的 []。BETWEEN

至于我所服务的客户的商业思维,在适当的情况下,我试图说服他们也经常使用半开。我见过很多情况,各种业务人员对报告中涵盖的时间段做出了不正确的假设。一致使用半开可以避免这些不幸的歧义。但是,如果客户坚持,我会在我的代码中注明这一点,并调整输入/输出,以便在我自己的逻辑中使用Half-Open。例如,我的逻辑使用星期一到星期一的一周,但在报表上减去一天来显示星期日。

有关使用半开方法表示时间跨度的更多类 [),请参阅其类(一对对象)和类(一对对象)的 ThreeTen-Extras 项目。IntervalInstantLocalDateRangeLocalDate

提示:打印/显示业务报表时,请包括一个描述查询逻辑的页脚,包括开始/结束的详细信息(包括包含/排除)。我在工作场所看到太多关于这一点的混乱,读者对日期范围(和其他标准)做出了不正确的假设。


关于 java.time

java.time 框架内置于 Java 8 及更高版本中。这些类取代了麻烦的旧日期时间类,如java.util.DateCalendarSimpleDateFormat

要了解更多信息,请参阅 Oracle 教程。搜索 Stack Overflow 以获取许多示例和解释。规格是JSR 310

Joda-Time 项目现在处于维护模式,建议迁移到 java.time 类。

您可以直接与数据库交换 java.time 对象。使用符合 JDBC 4.2 或更高版本的 JDBC 驱动程序。不需要字符串,不需要类。Hibernate 5 & JPA 2.2 支持 java.timejava.sql.*

从哪里获取 java.time 类?