date - 确定 Java 中时间范围表示的天数

标签 date time java-8

使用 Java 8 时间我只是想找出时间范围内表示的天数。考虑以下:

LocalDate start = LocalDate.of(2016, Month.MARCH, 28);
LocalDate end = LocalDate.of(2016, Month.MARCH, 31);
Period period = Period.between(start, end);

期间的天数为 3,表示 2 个日期之间的天数,包括开始和结束。我想要的是 2 个日期所代表的天数,实际上是 4(3 月 28 日、3 月 29 日、3 月 30 日、3 月 31 日)。

我知道我可以在从 Period.between() 返回的天数上加 1,但我想我很惊讶我找不到另一个调用来完全返回我想要的。我是否遗漏了什么或添加 1 是唯一的解决方案?

最佳答案

tl;博士

始终通过 半开 方法定义您的时间跨度,其中:

  • 开始是包容性的
  • 结尾是唯一的

  • 如果您想要 March 28, March 29, March 30, March 31 的四天,请从 3 月 28 日开始,在 4 月 1 日结束。从第一个(3 月 28 日)开始运行这些日期,直到但不包括最后一个(4 月 1 日)。

    2016-03-28/2016-04-01



    半开

    Am I missing something



    您可能没有意识到半开放方法在定义时间跨度方面的有用性。

    通常,定义时间跨度的最佳实践是半开放方法。在半开中,开始是包容的,而结束是独占的。

    这种方法解决了处理 小数秒 的问题。直觉上,许多程序员会试图找到最后可能的时刻作为时间跨度的结束。但最后一刻涉及无限可分的最后一秒。您可能会想,“好吧,只需将毫秒数保留到小数点后三位,中午午休结束时间为 12:59.59.999,因为这就是我所需要的所有分辨率,这就是遗留 java.util.Date 的分辨率。 util.Date 类。”。但是您将无法在您的数据库中找到匹配项,例如 Postgres 以微秒的分辨率存储日期时间值,12:59:59.999999。因此您决定使用小数点后六位,x .999999. 但是开始遇到与 java.time 类中的日期时间值不匹配的情况,并且您会了解到为九位小数秒 x.999999999 提供了纳秒分辨率。您可以使用半开法,结局一直持续到下一整秒,但不包括在内。

    我相信您会发现在整个日期时间处理代码中一致使用半开方法(无论是否涉及小数秒)将:
  • 使您的代码更易于阅读和理解。
  • 总体上减轻认知负担。了解所有时间跨度具有相同的定义可消除歧义。
  • 减少错误。

  • 例子:
  • 中午午餐时间从时钟敲响中午 (12:00:00) 的那一刻开始,一直持续到(但不包括)时钟敲响 1 点的那一刻。这意味着 12:00:00 到 13:00:00。
  • 一整天从一天的第一时刻开始(顺便说一下 not always 00:00:00 ),一直到但不包括第二天的第一时刻。
  • 一周从星期一开始,一直到(但不包括)下一个星期一。这意味着周一至周一的 7 天。
  • 一个月从当月的第一天开始,一直到下个月的第一天,但​​不包括下个月的第一天。所以3月份是3月1日到4月1日。

  • enter image description here
    LocalDate
    与其添加 1 以获得总天数,不如将您的时间跨度定义为半开放 :开始是包含的,结束是不包含的。如果您试图表示 3 月 28 日、29 日、30 日和 31 日这四个日期,那么我建议您定义一个从 3 月 28 日到 4 月 1 日的时间跨度。
    LocalDate start = LocalDate.of( 2016, Month.MARCH, 28 ) ; // inclusive
    LocalDate stop = LocalDate.of( 2016, Month.APRIL, 1 ) ; // exclusive
    
    Period
    java.time 类明智地使用了半开放方法。因此 Period.between 方法将结尾视为排他性的,如问题中所述。我建议你在这里随波逐流,而不是与之抗争。搜索 Stack Overflow 以获取更多有关此方法如何工作的示例。
    Period p = Period.between( start , stop );
    

    p.toString(): P4D


    ChronoUnit
    如果您想要总天数,例如一个半月的 45 天,请使用 ChronoUnit 枚举,这是 TemporalUnit 的实现。参见 this Question 进行讨论。

    同样,java.time 类使用半开放方法。所以
    long daysBetween = ChronoUnit.DAYS.between( start, stop );
    

    4



    实时代码

    请参阅此示例 code run live at IdeOne.com

    关于date - 确定 Java 中时间范围表示的天数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41833781/

    相关文章:

    python - 在 Python 中使用列表理解查找最小/最大日期

    mysql - MySQL 中的 '2018-03-22 00:00:00"有什么问题?

    java - 我如何在 Seam 中插入今天的日期?

    java - 为什么我传递给 Arrays.sort 的方法引用需要是静态的?

    ruby - 如何在几秒钟内获得前导 0?

    ruby - 将基于字符串的分钟和秒值相加

    time - 在 Rails 3 中使用 distance_of_time_in_words

    C++-Build : After editing a file in a project the build process takes a long time. 如何找出负责的文件/类?

    java - hibernate-java8 依赖项无助于正确保存日期

    java - 将日期或日期时间都解析为 Java 8 中的 LocalDateTime