diff --git a/carbon.go b/carbon.go index fa61864..ef16c84 100644 --- a/carbon.go +++ b/carbon.go @@ -1195,50 +1195,40 @@ func (c *Carbon) DiffInMonths(carb *Carbon, abs bool) int64 { return calculateDiffInMonths(cAux, carbAux, abs) } -func calculateDiffInMonths(c, carb *Carbon, abs bool) int64 { +func calculateDiffInMonths(c *Carbon, carb *Carbon, abs bool) int64 { if c.Month() == carb.Month() && c.Year() == carb.Year() { return 0 } - if c.Month() != carb.Month() && c.Year() == carb.Year() { - diffInMonths := int64(carb.Month() - c.Month()) - remainingTime, totalHours := calculateDiffInTimeAndHours(c, carb) + diffInDays := c.DiffInDays(carb, false) - if remainingTime < totalHours { - return 0 - } - - return absValue(abs, diffInMonths) - } + end := c.Copy() + start := carb.Copy() + reg := -int64(1) - m := monthsPerYear - c.Month() + carb.Month() - 1 - if c.Year() < carb.Year() && c.hasRemainingHours(carb) { - m = m + 1 + if diffInDays > 0 { + end = carb.Copy() + start = c.Copy() + reg = int64(1) } - if c.Year() > carb.Year() { - m = monthsPerYear - carb.Month() + c.Month() - 1 + months := calculateFromMonthToMonth(start, end, 0) - if carb.hasRemainingHours(c) { - m = m + 1 - } - } + return absValue(abs, int64(months*reg)) +} - diffYr := c.Year() - carb.Year() - if math.Abs(float64(diffYr)) > 1 { - dateWithoutMonths := c.AddMonths(int(m)) - diff := dateWithoutMonths.DiffInYears(carb, abs)*monthsPerYear + int64(m) +func calculateFromMonthToMonth(start *Carbon, end *Carbon, months int64) int64 { + date := start.AddDays(start.DaysInMonth()) + diffInDays := date.DiffInDays(end, false) + diffInSeconds := date.DiffInSeconds(end, false) - return absValue(abs, diff) + if diffInDays < 0 || diffInDays == 0 && diffInSeconds < 0 { + return months } - diff := int64(m) + months += 1 - if c.GreaterThan(carb) { - diff = -diff - } - - return absValue(abs, diff) + return calculateFromMonthToMonth(date, end, months) } func (c *Carbon) hasRemainingHours(carb *Carbon) bool { @@ -1838,14 +1828,6 @@ func (c *Carbon) SetLocale(l string) error { return nil } -func calculateDiffInTimeAndHours(c, carb *Carbon) (int, int) { - if carb.Timestamp() < c.Timestamp() { - return int(c.DiffInHours(carb, true)), carb.DaysInMonth() * hoursPerDay - } - - return int(carb.DiffInHours(c, true)), c.DaysInMonth() * hoursPerDay -} - /* TODO // String Formatting diff --git a/carbon_test.go b/carbon_test.go index a849d62..6cb9bd4 100644 --- a/carbon_test.go +++ b/carbon_test.go @@ -1935,6 +1935,14 @@ func TestDiffInMonthsTimeZone(t *testing.T) { t1, _ := Create(2016, time.August, 18, 10, 0, 0, 0, "UTC") t2, _ := Create(2016, time.January, 18, 12, 0, 0, 0, "Europe/Madrid") + // On January the diff from UTC and Europe/Madrid is only one hour + assert.EqualValues(t, 6, t1.DiffInMonths(t2, true)) +} + +func TestDiffInMonthsTimeZoneWithSameTimeDiff(t *testing.T) { + t1, _ := Create(2016, time.August, 18, 10, 0, 0, 0, "UTC") + t2, _ := Create(2016, time.January, 18, 11, 0, 0, 0, "Europe/Madrid") + assert.EqualValues(t, 7, t1.DiffInMonths(t2, true)) } @@ -1966,6 +1974,13 @@ func TestDiffInMonthsMoreThanTwoYears(t *testing.T) { assert.EqualValues(t, 82, t1.DiffInMonths(t2, true)) } +func TestDiffInMonthsTwoOverlapingYears(t *testing.T) { + t1, _ := Create(2019, 07, 1, 0, 0, 0, 0, time.UTC.String()) + t2, _ := Create(2021, 07, 24, 0, 0, 0, 0, time.UTC.String()) + + assert.EqualValues(t, 24, t1.DiffInMonths(t2, true)) +} + func TestDiffInMonthsOneDayDifference(t *testing.T) { t1, _ := Create(2016, time.September, 1, 10, 0, 0, 0, "UTC") t2, _ := Create(2016, time.August, 31, 10, 0, 0, 0, "UTC")