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

时间:2017-01-24 16:48:29

标签: 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,表示两个日期之间的天数,包括开始日期和结束日期。我想要的是两个日期所代表的天数,实际上是4天(3月28日,3月29日,3月30日,3月31日)。

我知道我可以加上从Period.between()返回的天数加1,但我想我很惊讶我找不到另一个回复我想要的东西。我错过了什么或者只添加1个解决方案吗?

4 个答案:

答案 0 :(得分:5)

TL;博士

始终通过 半开放 方法定义您的时间范围,其中:

  • 开头包含
  • 结尾独占

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

  

2016年3月28日/ 2016年4月1日

半开

  

我错过了什么

您可能会对半开放方法在定义时间跨度方面的实用性缺乏认识。

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

这种方法解决了处理小数秒的问题。直观地说,许多程序员将试图找到最后一个可能的时刻作为一段时间的结束。但最后一刻涉及到无限可分的最后一秒。你可能会想,"嗯,只是在中午休息时间结束时前往小数点后三位,12:59.59.999,因为这是我将需要的所有分辨率,这就是遗留java.util.Date类。“但是你将无法在你的数据库中找到像Postgres那样的匹配项,它们以微秒12:59:59.999999的分辨率存储日期时间值。所以你决定使用小数的六位小数,x.999999。但是开始遇到与java.time类中的日期时间值不匹配的情况,并且您学习了提供分数秒的九位数x.999999999的纳秒分辨率。你可以通过使用半开放式方法来解决这个令人沮丧的错误轮播,其结尾可以达到但不包括下一整秒。

我相信您会发现在整个日期时间处理代码中一致使用半开放式方法(无论是否涉及小数秒):

  • 让您的代码更易于阅读和理解。
  • 减轻整体的认知负担。
    了解所有时间跨度相同的定义消除了模糊性。
  • 减少错误。

示例:

  • 中午午餐时段从时钟敲响中午(12:00:00)开始,一直运行到但不包括时钟敲响一时的时刻。这意味着12:00:00至13:00:00。
  • 一整天从第一天开始(not always 00:00:00,顺便说一下),然后运行到第二天的第一个时刻,但不包括第二天。
  • 一周从星期一开始,一直运行到下一个星期一,但不包括在内。这意味着周一至周一的七天。
  • 月份的第一个月开始,一直持续到下个月的第一个月,但不包括在内。所以三月是三月一日到四月一日。

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

答案 1 :(得分:2)

PeriodLocalDate中,似乎并不是一个包容性的结束日期方法,因此似乎唯一要做的事情就是:

Period.between(start, end.plusDays(1))

start.until(end.plusDays(1))

Period.between只调用LocalDate.until

答案 2 :(得分:1)

我相信你的日常计数与java不同。 Period.between根据文档:http://docs.oracle.com/javase/8/docs/api/java/time/Period.html#between-java.time.LocalDate-java.time.LocalDate- “包括开始日期,但结束日期不包括在内。”考虑到这一点 - 是的,添加1是唯一的解决方案。

答案 3 :(得分:0)

方法的签名是

between(LocalDate startDateInclusive, LocalDate endDateExclusive) {

并且该方法没有被加载,除了在给定结果中添加1之外别无选择......