时间间隔的包容性/独占性是否有标准?

时间:2012-03-20 21:38:19

标签: java date time conventions

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

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

  1. (A,B) - 两端都是独家的。
  2. [A,B] - 两端都是包容性的。
  3. [A,B) - 开始是包容性的,结束是独占的
  4. (A,B) - 开始是独占的,结束是包容性的
  5. 每一个都有不同的特点(我认为,随意指出更多)

    [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中运行良好的答案。

6 个答案:

答案 0 :(得分:45)

在一般情况下,[A, B)有很多内容,我没有看到为什么时间间隔不同的原因。

Djikstra写了一篇关于它的好文章Why numbering should start at zero,尽管有这个名字,但大部分都是这样做的。

优点简述:

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

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

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

使用包含上限编写相同的内容会导致许多错误因一个错误而丢失。

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

答案 1 :(得分:5)

我会提供我为团队所写的内容作为使用Voo链接的答案,直到Voo添加答案为止,然后我会给予他信任。这就是我为我们的案子做出的决定:

  

我们的应用程序中的时间间隔将表示为一对   具有开始时间的约定的瞬时时间   包容性和结束时间是独家的。这个惯例是   在数学上方便,边界的差异是   等于间隔的长度,也是数字的   与数组和列表在java中下标的方式一致   程序(见http://www.cs.utexas.edu/~EWD/ewd08xx/EWD831.PDF)。该   实际结果是间隔2012-03-17T00:00:00.000Z -   2012-03-18T00:00:00.000Z表示整个圣帕特里克节,   从2012-03-17开始的每个日期都将被确定为   包括在圣帕特里克节,但2012-03-18T00:00:00.000Z将不会   包括在内,圣帕特里克节将包括24 * 60 * 60 * 1000   毫秒。

答案 2 :(得分:2)

我不能肯定地说,但我怀疑是否存在标准或惯例。您是否包含开始或结束时刻将取决于您的用例,因此请考虑它们对您是否重要。如果决定是任意的,请选择一个,注意选择是任意的并继续。

对于Java支持的内容,Joda Time库实现了包含开始时间而不是结束时间的Interval

答案 3 :(得分:2)

尽管这个主题更多地关注Java,但我认为看到其他采用的约定是非常有趣的,特别是考虑到pandas Python library现在无处不在于数据分析,而且事实上,当查找关于时间范围的包含性/排他性的约定时,此StackOverflow页面是最热门的搜索结果之一。

引用this page

  

开始和结束日期严格包含在内。因此,如果指定,它将不会在这些日期之外生成任何日期。

此外,它不仅生成日期范围。在尝试索引时间序列数据时也采用该约定。这是对DatetimeIndex

的数据框的简单测试
>>> import pandas as pd
>>> pd.__version__
'0.20.2'
>>> df = pd.DataFrame(list(range(20)))
>>> df.index = pd.date_range(start="2017-07-01", periods=20)
>>> df["2017-07-01":"2017-07-05"]
            0
2017-07-01  0
2017-07-02  1
2017-07-03  2
2017-07-04  3
2017-07-05  4

答案 4 :(得分:2)

java.time&半开

取代麻烦的遗留日期时间类以及Joda-Time项目的java.time类使用半开放方法定义时间跨度[),其中起点包含,而结尾是独占

对于具有小数秒的日期时间,这消除了尝试捕捉最后时刻的问题。必须解决无限可分的最后一秒,但各种系统使用各种粒度,例如毫秒,微秒,纳秒或其他。例如,半开,一天开始于一天中的第一时刻并且一直运行,但包括,第二天的第一个时刻。问题解决了,不需要与当天的最后一刻和它的第二小时搏斗。

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

一致使用Half-Open [)的另一个好处是,每当我必须检测并解密和验证一段代码的时间跨度方法时,就会减轻认知负荷。在我自己的编程中,我只是简单地在顶部的评论中提到半开放,我立即知道如何阅读该代码。

一致使用Half-Open的结果是减少了我的代码中的错误的机会,因为我的思维和写作风格是统一的,没有机会混淆包容性 - 排他性。

顺便说一下,注意Half-Open [)意味着避免SQL BETWEEN连接,因为它始终是完全关闭的[]。

至于我服务的客户的商业思维,在适当的时候,我试图说服他们不断使用半开放。我已经看到很多情况,各种商业人士对报告中涉及的时间段做出了错误的假设。一致使用半开放避免了这些不幸的含糊之处。但是如果客户坚持,我会在我的代码中注意这一点并调整输入/输出,以便在我自己的逻辑中使用半开放。例如,我的逻辑使用周一至周一的一周,但在报告中减去一天显示星期日。

对于使用半开放式方法表示更多时间范围的类,请参阅 ThreeTen-Extras 项目的Interval类(一对Instant对象)和LocalDateRange类(一对LocalDate个对象)。

关于java.time

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

现在位于Joda-Timemaintenance mode项目建议迁移到java.time类。

要了解详情,请参阅Oracle Tutorial。并搜索Stack Overflow以获取许多示例和解释。规范是JSR 310

从哪里获取java.time类?

ThreeTen-Extra项目使用其他类扩展java.time。该项目是未来可能添加到java.time的试验场。您可以在此处找到一些有用的课程,例如IntervalYearWeekYearQuartermore

答案 5 :(得分:1)

我刚刚完成了这个完全相同的思考过程,我认为这在某种程度上是标准化的,或者至少通过这些类型的Q& A帖子来澄清是非常重要的!

在我们的案例中,所讨论的日期范围用作微服务的输入和输出;至少在短期内会被现有的单片应用程序调用(它是一个整体分解项目)。因此,我认为上述与业务需求驱动的决策相关的评论在我们的案例中不太相关(因为直接"用户"软件我们'重建真的是技术人员。如果我们处理日期选择器的输入可能是另一个故事!

我的建议是所有开始日期都是包含在内的,并且所有结束日期都是独占的 - 所以[A,B]在你的符号中。这是出于以下原因:

  1. 我们之前已同意,任何包含时间部分的传入日期都将被拒绝(即使JSON值为" 2018-01-01T00:00:00")并且我们' d输出所有日期没有时间。因此,如果结束日期是独占的,那么只要将字符串反序列化为.NET DateTime对象,就会过了一天。

  2. 我喜欢这样的想法:日期范围(在我们的情况下应该总是产生整天)总是可以通过简单地执行dateRange =(endDateExcl - startDateIncl).TotalDays来计算。无需在任何地方添加1个!

  3. 该服务执行的大部分业务验证都是检查多个数据范围是否相互冲突,没有间隙。当使用[A,B]时,这很容易检查,因为每个B应该与前面的A匹配。如果我们选择[A,B],那么我们(开发人员,测试人员,支持工程师)经常会问自己"三月又过了几天?" (例如[2018-03-01,2018-03-30],[2018-04-01,2018-04-30])或" 2016年是否有闰日?" (例如[2016-02-01,2016-02-28],[2016-03-01,2016-03-30])。

  4. 只是添加,我强烈建议任何人,无论决定,明确地后缀所有属性名称,变量,方法或其他与" Incl"或者" Excl"这样每个人都可以清楚地看到文档!

    我们还建议所有日期都应采用ISO格式,以及任何带有" Z"最后也应该被拒绝(因为我们的理解是我们整天都在工作,并且我们不希望将日期反序列化为带有流氓时间(或23!)的DateTime对象,因为夏令时)。

    脚注,我可能会发布这个作为对Voo回答的评论,但我只是(姗姗来迟!)加入SO并且需要在我能做到之前赢得我的荣誉! ; - )

    快乐约会x