Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 10 additions & 1 deletion src/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,16 @@ const monthDiff = (a, b) => {
// function from moment.js in order to keep the same result
if (a.date() < b.date()) return -monthDiff(b, a)
const wholeMonthDiff = ((b.year() - a.year()) * 12) + (b.month() - a.month())
const anchor = a.clone().add(wholeMonthDiff, C.M)
let anchor = a.clone().add(wholeMonthDiff, C.M)
// #1000 A Feb 29 anniversary does not exist in a non-leap year: `add`
// clamps it to Feb 28, which makes `diff` report a full year one day
// early (a person born on 2016-02-29 turns 1 on 2017-03-01, not on
// 2017-02-28). Roll such anchors over to Mar 1, following the common
// legal convention for leap-day anniversaries.
if (a.month() === 1 && a.date() === 29
&& anchor.month() === 1 && anchor.date() === 28) {
anchor = anchor.add(1, C.D)
}
const c = b - anchor < 0
const anchor2 = a.clone().add(wholeMonthDiff + (c ? -1 : 1), C.M)
return +(-(wholeMonthDiff + ((b - anchor) / (c ? (anchor - anchor2) :
Expand Down
13 changes: 13 additions & 0 deletions test/display.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,19 @@ describe('Difference', () => {
expect(dayjs('2018-01-01').diff(dayjs('2018-01-01'), 'month')).toEqual(0)
})

it('MonthDiff for leap-day anniversaries (#1000)', () => {
// a leap-day anniversary rolls over to Mar 1 in non-leap years
expect(dayjs('2017-02-28').diff(dayjs('2016-02-29'), 'year')).toEqual(0)
expect(dayjs('2017-03-01').diff(dayjs('2016-02-29'), 'year')).toEqual(1)
expect(dayjs('2017-02-28').diff(dayjs('2016-02-29'), 'month')).toEqual(11)
expect(dayjs('2017-03-01').diff(dayjs('2016-02-29'), 'month')).toEqual(12)
// leap-year anniversaries are unaffected
expect(dayjs('2020-02-28').diff(dayjs('2016-02-29'), 'year')).toEqual(3)
expect(dayjs('2020-02-29').diff(dayjs('2016-02-29'), 'year')).toEqual(4)
// non leap-day boundaries keep clamping to end of month
expect(dayjs('2016-02-29').diff(dayjs('2016-01-31'), 'month')).toEqual(1)
})

it('undefined edge case', () => {
expect(dayjs().diff(undefined, 'seconds')).toBeDefined()
})
Expand Down