cperriard cperriard - 1 year ago 95
Scala Question

A Bug in java time calculating months between 2 dates

When using java.time in Scala I experienced a strange behavior. I want to calculate the number of months between two dates like this:

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

Is this a bug or do I have got it all wrong?

org.joda.time works as I would expect it:

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

When adding months to a java.time.LocalDate it works fine:

// java.time.LocalDate = 2015-04-30

Answer Source

This is not a bug, and it is behaving like expected (see also JDK-8152384 and JDK-8037392, which were closed as "Not An Issue"). Joda Time and the Java Time API have different behaviour regarding this. Quoting Stephen Colebourne from the previous bug report:

The OP appears to want a rule where the days are calculated based on the original month length, not the one that results once the month-year difference is applied. The OP is not wrong, its just that its not how we choose to make the calculation in java.time.

Indeed, from Period.between:

The period is calculated by removing complete months, then calculating the remaining number of days, adjusting to ensure that both have the same sign. [...] A month is considered to be complete if the end day-of-month is greater than or equal to the start day-of-month.

Between the 31st of March, and the 30th of April, no complete month has elapsed. As such, you have a period containing the number of days between the two dates, which is 30. To have the complete month of April elapsed, you need to add one day to the end date, and make it the 1st of June.

Joda has a different way of calculating the month period. From Months.monthsBetween:

This method calculates by adding months to the start date until the result is past the end date. As such, a period from the end of a "long" month to the end of a "short" month is counted as a whole month.

Joda explicitly takes the variable number of days in a month into account when calculating the number of months between the two dates. Java Time doesn't.