2016-09-14 175 views
1

在Scala中使用java.time時,我遇到了一個奇怪的行爲。我想計算這樣的兩個日期之間的月份數:在兩個日期之間計算月份的java錯誤

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 
+1

它是否違反了明確規定的規範? –

+0

@MarkoTopolnik:我不知道它是否確實如此,但我預計一個月可能會有不同的天數。 – cperriard

+0

如果它打破規範,這是一個錯誤;如果沒有,那麼它只會打破你的(合理的)期望。 –

回答

5

這不是一個錯誤,它的行爲與預期相同(另請參閱JDK-8152384JDK-8037392,它們被視爲「不是問題」)。 Joda Time和Java Time API在這方面有不同的行爲。引用斯蒂芬Colebourne對from the previous bug report

的OP似乎想在那裏的日子是在原有基礎上一個月的長度,而不是一旦施加月 - 年的差異導致了一個計算的規則。 OP沒有錯,只是它不是我們如何選擇在java.time中進行計算。

事實上,從Period.between

期間通過去除完整個月,然後計算天的剩餘數量,調整,以確保兩個具有相同的符號計算。 [...]如果結束的月份日期大於或等於月份的開始日期,則認爲該月份已完成。

在3月31日和4月30日之間,沒有完成月已過。因此,您有一段時間包含兩個日期之間的天數,即30。要完成4月份的整個月份,您需要在結束日期添加一天,並將其設置爲6月1日。

喬達有不同的計算月份期間的方法。從Months.monthsBetween

該方法通過將月份添加到開始日期直到結果超過結束日期來計算。因此,從「長」月結束到「短」月結束的時間段被計爲整個月。

在計算兩個日期之間的月數時,Joda明確考慮了一個月中的可變天數。 Java時間不。

+0

感謝您的鏈接。 Period(startDate,endDate)和Period(endDate,startDate)的結果可能有很大差異的事實是違反直覺並且有點可怕的說實話: –

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)

+0

我意識到這一點。但爲什麼'Period.between(LocalDate.parse(「2015-04-30」),LocalDate.parse(「2015-05-30」))'返回P1M? – cperriard

+0

@cperriard因爲那是相隔一個月。爲什麼你會期望一個短的時間是相同的? –

+0

@PeterLawrey因爲4月份只有30天,並且因爲'java.time.LocalDate.parse(「2015-03-31」)。plusMonths(1)'返回2015-04-30。 – cperriard

2

我同意這是一個有點出乎意料,但它是正確的結果,如果你考慮到javadoc。 來自javadoc

包括開始日期,但結束日期不包括。 通過移除完整的月份計算期間,然後計算剩餘天數,調整以確保兩者具有相同的符號。然後根據12個月的年份將月份分成幾年和幾個月。 如果結束的月份日期大於或等於開始的月份日期,則考慮一個月。例如,從2010-01-15到2011-03-18是一年,兩個月和三天。

區別來自「完整月份」的含義。 在這種情況下,4月1日至5月1日(獨家)被認爲是一個完整的月份,而3月31日至4月30日(獨家)則不是。

+0

請鏈接到Javadoc。我也試圖查看這一點,但顯然沒有看到正確的地方。 –

相關問題