diff --git a/carbon.go b/carbon.go index b2f5105..990605a 100644 --- a/carbon.go +++ b/carbon.go @@ -1181,46 +1181,54 @@ func (c *Carbon) DiffInMonths(carb *Carbon, abs bool) int64 { return 0 } - diffHr := c.DiffInHours(carb, abs) - hrLastMonth := int64(c.DaysInMonth() * hoursPerDay) - - if (diffHr - hrLastMonth) >= 0 { - var m int64 - if c.Year() < carb.Year() { - m = (int64(monthsPerYear) - int64(c.In(time.UTC).Month())) + (int64(carb.In(time.UTC).Month()) - 1) - totalHr := int64(c.DaysInMonth() * hoursPerDay) - cHr := c.StartOfMonth().DiffInHours(c, abs) - remainHr := totalHr - cHr - spentInHr := carb.StartOfMonth().DiffInHours(carb, abs) - if (remainHr + spentInHr) >= totalHr { - m = m + 1 - } - } else if c.Year() > carb.Year() { - m = (int64(monthsPerYear) - int64(carb.In(time.UTC).Month())) + (int64(c.In(time.UTC).Month()) - 1) - totalHr := int64(carb.DaysInMonth() * hoursPerDay) - carbHr := carb.StartOfMonth().DiffInHours(carb, abs) - remainHr := totalHr - carbHr - spentInHr := c.StartOfMonth().DiffInHours(c, abs) - if (remainHr + spentInHr) >= totalHr { - m = m + 1 - } - } else { - m = int64(carb.In(time.UTC).Month() - c.In(time.UTC).Month()) + if c.Month() != carb.Month() && c.Year() == carb.Year() { + diffInMonths := int64(carb.In(time.UTC).Month() - c.In(time.UTC).Month()) + remainingTime := int(carb.DiffInHours(c, true)) + + if remainingTime < c.DaysInMonth()*hoursPerDay { + return 0 } - diffYr := c.Year() - carb.Year() - if math.Abs(float64(diffYr)) > 1 { - diff := c.DiffInYears(carb, abs)*monthsPerYear + m + return absValue(abs, diffInMonths) + } + + m := monthsPerYear - c.In(time.UTC).Month() + carb.In(time.UTC).Month() - 1 + if c.Year() < carb.Year() && c.hasRemainingHours(carb) { + m = m + 1 + } + + if c.Year() > carb.Year() { + m = monthsPerYear - carb.In(time.UTC).Month() + c.In(time.UTC).Month() - 1 - return absValue(abs, diff) + if carb.hasRemainingHours(c) { + m = m + 1 } + } - diff := m + diffYr := c.Year() - carb.Year() + if math.Abs(float64(diffYr)) > 1 { + dateWithoutMonths := c.AddMonths(int(m)) + diff := dateWithoutMonths.DiffInYears(carb, abs)*monthsPerYear + int64(m) return absValue(abs, diff) } - return 0 + diff := int64(m) + + if c.GreaterThan(carb) { + diff = -diff + } + + return absValue(abs, diff) +} + +func (c *Carbon) hasRemainingHours(carb *Carbon) bool { + totalHr := int64(c.DaysInMonth() * hoursPerDay) + cHr := c.StartOfMonth().DiffInHours(c, false) + remainHr := totalHr - cHr + spentInHr := carb.StartOfMonth().DiffInHours(carb, false) + + return remainHr+spentInHr >= totalHr } // DiffDurationInString returns the duration difference in string format diff --git a/carbon_test.go b/carbon_test.go index 226fcd0..3b8e400 100644 --- a/carbon_test.go +++ b/carbon_test.go @@ -1993,6 +1993,76 @@ func TestDiffInMonthsSameMonth(t *testing.T) { assert.EqualValues(t, 0, t1.DiffInMonths(t2, true)) } +func TestDiffInMonthsDifferentYears(t *testing.T) { + t1, _ := Create(2018, time.May, 1, 0, 0, 0, 0, "UTC") + t2, _ := Create(2020, time.June, 1, 0, 0, 0, 0, "UTC") + + assert.EqualValues(t, 25, t1.DiffInMonths(t2, true)) +} + +func TestDiffInMonthsPositive(t *testing.T) { + t1, _ := Create(2018, time.January, 1, 0, 0, 0, 0, "UTC") + t2, _ := Create(2019, time.February, 1, 0, 0, 0, 0, "UTC") + + assert.EqualValues(t, 13, t1.DiffInMonths(t2, true)) +} + +func TestDiffInMonthsNegativeWithSign(t *testing.T) { + t1, _ := Create(2018, time.January, 1, 0, 0, 0, 0, "UTC") + t2, _ := Create(2017, time.February, 1, 0, 0, 0, 0, "UTC") + + assert.EqualValues(t, -11, t1.DiffInMonths(t2, false)) +} + +func TestDiffInMonthsNegativeWithSignOneHourLess(t *testing.T) { + t1, _ := Create(2018, time.January, 1, 0, 0, 0, 0, "UTC") + t2, _ := Create(2017, time.January, 1, 1, 0, 0, 0, "UTC") + + assert.EqualValues(t, -11, t1.DiffInMonths(t2, false)) +} + +func TestDiffInMonthsNegativeWithSignWithMonthsLess(t *testing.T) { + t1, _ := Create(2018, time.January, 1, 0, 0, 0, 0, "UTC") + t2, _ := Create(2017, time.July, 1, 0, 0, 0, 0, "UTC") + + assert.EqualValues(t, -6, t1.DiffInMonths(t2, false)) +} + +func TestDiffInMonthsNegativeWithSignWithOneMonthLess(t *testing.T) { + t1, _ := Create(2018, time.January, 1, 0, 0, 0, 0, "UTC") + t2, _ := Create(2017, time.December, 1, 0, 0, 0, 0, "UTC") + + assert.EqualValues(t, -1, t1.DiffInMonths(t2, false)) +} + +func TestDiffInMonthsNegativeWithSignWithOneMonthAndOneHourLess(t *testing.T) { + t1, _ := Create(2018, time.January, 1, 0, 0, 0, 0, "UTC") + t2, _ := Create(2017, time.December, 1, 1, 0, 0, 0, "UTC") + + assert.EqualValues(t, 0, t1.DiffInMonths(t2, false)) +} + +func TestDiffInMonthsNegativeWithFewDaysLeft(t *testing.T) { + t1, _ := Create(2018, time.January, 1, 0, 0, 0, 0, "UTC") + t2, _ := Create(2017, time.December, 20, 0, 0, 0, 0, "UTC") + + assert.EqualValues(t, 0, t1.DiffInMonths(t2, false)) +} + +func TestDiffInMonthsNegativeNoSign(t *testing.T) { + t1, _ := Create(2018, time.January, 1, 0, 0, 0, 0, "UTC") + t2, _ := Create(2017, time.February, 1, 0, 0, 0, 0, "UTC") + + assert.EqualValues(t, 11, t1.DiffInMonths(t2, true)) +} + +func TestDiffInMonthsEnsureIsTruncated(t *testing.T) { + t1, _ := Create(2018, time.January, 1, 0, 0, 0, 0, "UTC") + t2, _ := Create(2018, time.February, 17, 0, 0, 0, 0, "UTC") + + assert.EqualValues(t, 1, t1.DiffInMonths(t2, true)) +} + func TestDiffInString(t *testing.T) { t1, _ := Create(2016, time.August, 10, 10, 0, 0, 0, "UTC") t2, _ := Create(2016, time.August, 1, 23, 0, 0, 0, "UTC")