在Scala中使用java.time时,我遇到了一种奇怪的行为。我想计算这两个日期之间的月数:
import java.time._
Period.between(LocalDate.parse("2015-03-31"), LocalDate.parse("2015-04-30"))
// java.time.Period = P30D
// I would expect java.time.Period = P1M
Period.between(LocalDate.parse("2015-03-31"), LocalDate.parse("2015-05-01"))
// java.time.Period = P1M1D
这是一个错误还是我错了?
org.joda.time正如我所期望的那样工作:
import org.joda.time.DateTime
import org.joda.time.Months
Months.monthsBetween( new DateTime().withDate(2015, 3, 31), new DateTime().withDate(2015, 4, 30))
//org.joda.time.Months = P1M
在java.time.LocalDate中添加月份时,它可以正常工作:
java.time.LocalDate.parse("2015-03-31").plusMonths(1)
// java.time.LocalDate = 2015-04-30
答案 0 :(得分:5)
这不是一个错误,它表现得像预期的那样(另见JDK-8152384和JDK-8037392,它们被关闭为“不是问题”)。 Joda Time和Java Time API对此有不同的行为。引用Stephen Colebourne from the previous bug report:
OP似乎想要一个规则,其中天数是根据原始月份长度计算的,而不是在应用月份年度差异后计算的天数。 OP没有错,只是因为我们没有选择在java.time中进行计算。
确实,来自Period.between
:
通过删除完整月份,然后计算剩余天数来计算期间,调整以确保两者具有相同的符号。 [...]如果结束日期大于或等于月初日,则认为一个月完成。
在3月31日和4月30日之间,没有完成月。因此,您有一个句点,其中包含两个日期之间的天数,即30个。要完成整月4月,您需要在结束日期添加一天,并将其设置为6月1日。 / p>
Joda有一种不同的计算月份的方法。来自Months.monthsBetween
:
此方法通过将月份添加到开始日期直到结果超过结束日期来计算。因此,从“长”月结束到“短”月结束的期间计为整月。
在计算两个日期之间的月数时,Joda明确地将一个月中的可变天数考虑在内。 Java Time没有。
答案 1 :(得分:2)
我同意这有点出乎意料,但如果考虑到javadoc,这是正确的结果。 来自javadoc
包含开始日期,但结束日期不包括在内。 通过删除完整月份,然后计算剩余天数来计算期间,调整以确保两者具有相同的符号。然后根据12个月的年份将月数分成几年和几个月。 如果结束日期大于或等于月初,则会考虑一个月。例如,从2010-01-15到2011-03-18是一年,两个月和三天。
差异来自于完整的一个月"手段。 在这种情况下,4月1日至5月1日(独家)被视为完整月份,而3月31日至4月30日(不包括)则不是。
答案 2 :(得分:1)
我相信Period.between
在第一个示例中返回P30D
,因为第二个参数是独占的。这是根据https://docs.oracle.com/javase/8/docs/api/java/time/Period.html#between-java.time.LocalDate-java.time.LocalDate-
public static Period between(LocalDate startDateInclusive, LocalDate endDateExclusive)