Skip to content

Commit

Permalink
Merge pull request #285 from lilyinstarlight/fix/relative-time-at-end…
Browse files Browse the repository at this point in the history
…-of-longer-months

Correctly count month durations relative to the end of longer months
  • Loading branch information
keithamus authored Jun 10, 2024
2 parents ed0833b + 60fb1ef commit 7db58b3
Show file tree
Hide file tree
Showing 3 changed files with 35 additions and 6 deletions.
14 changes: 10 additions & 4 deletions src/duration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -153,16 +153,23 @@ export function roundToSingleUnit(duration: Duration, {relativeTo = Date.now()}:

// Resolve calendar dates
const currentYear = relativeTo.getFullYear()
let currentMonth = relativeTo.getMonth()
const currentMonth = relativeTo.getMonth()
const currentDate = relativeTo.getDate()
if (days >= 27 || years + months + days) {
const newMonthDate = new Date(relativeTo)
newMonthDate.setDate(1)
newMonthDate.setMonth(currentMonth + months * sign + 1)
newMonthDate.setDate(0)
const monthDateCorrection = Math.max(0, currentDate - newMonthDate.getDate())

const newDate = new Date(relativeTo)
newDate.setFullYear(currentYear + years * sign)
newDate.setDate(currentDate - monthDateCorrection)
newDate.setMonth(currentMonth + months * sign)
newDate.setDate(currentDate + days * sign)
newDate.setDate(currentDate - monthDateCorrection + days * sign)
const yearDiff = newDate.getFullYear() - relativeTo.getFullYear()
const monthDiff = newDate.getMonth() - relativeTo.getMonth()
const daysDiff = Math.abs(Math.round((Number(newDate) - Number(relativeTo)) / 86400000))
const daysDiff = Math.abs(Math.round((Number(newDate) - Number(relativeTo)) / 86400000)) + monthDateCorrection
const monthsDiff = Math.abs(yearDiff * 12 + monthDiff)
if (daysDiff < 27) {
if (days >= 6) {
Expand All @@ -180,7 +187,6 @@ export function roundToSingleUnit(duration: Duration, {relativeTo = Date.now()}:
years = yearDiff * sign
}
if (months || years) days = 0
currentMonth = relativeTo.getMonth()
}
if (years) months = 0

Expand Down
9 changes: 7 additions & 2 deletions test/duration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -367,6 +367,9 @@ suite('duration', function () {
['-P55D', [-1, 'month'], {relativeTo: '2023-02-27T22:22:57Z'}],
['-P65D', [-3, 'month'], {relativeTo: '2023-02-28T22:22:57Z'}],
['-P75D', [-3, 'month'], {relativeTo: '2023-03-09T22:22:57Z'}],
['P1M', [1, 'month'], {relativeTo: '2024-05-31T00:00:00Z'}],
['-P1M', [-1, 'month'], {relativeTo: '2024-05-31T00:00:00Z'}],
['-P3M', [-3, 'month'], {relativeTo: '2023-05-30T00:00:00Z'}],
[
'P8M',
[8, 'month'],
Expand Down Expand Up @@ -396,6 +399,8 @@ suite('duration', function () {
},
],
['P1M1D', [1, 'month'], {relativeTo: new Date('2022-12-01T00:00:00Z')}],
['P1M1D', [2, 'month'], {relativeTo: new Date('2023-01-31T00:00:00Z')}],
['P1M30D', [2, 'month'], {relativeTo: new Date('2023-01-31T00:00:00Z')}],
[
'P9M20DT25H',
[9, 'month'],
Expand Down Expand Up @@ -478,14 +483,14 @@ suite('duration', function () {
],
])
for (const [input, [val, unit], opts] of relativeTests) {
test(`getRelativeTimeUnit(${input}) === [${val}, ${unit}]`, () => {
test(`getRelativeTimeUnit(${input}${opts ? `, ${JSON.stringify(opts)}` : ''}) === [${val}, ${unit}]`, () => {
assert.deepEqual(
getRelativeTimeUnit(Duration.from(input), opts || {relativeTo: new Date('2023-07-01T00:00:00')}),
[val, unit],
)
})
if (opts?.relativeTo) continue
test(`getRelativeTimeUnit(-${input}) === [-${val}, ${unit}]`, () => {
test(`getRelativeTimeUnit(-${input}${opts ? `, ${JSON.stringify(opts)}` : ''}) === [-${val}, ${unit}]`, () => {
assert.deepEqual(
getRelativeTimeUnit(Duration.from(`-${input}`), opts || {relativeTo: new Date('2023-07-01T00:00:00')}),
[-val, unit],
Expand Down
18 changes: 18 additions & 0 deletions test/relative-time.js
Original file line number Diff line number Diff line change
Expand Up @@ -482,6 +482,24 @@ suite('relative-time', function () {
assert.equal(time.shadowRoot.textContent, '4 months ago')
})

test('rewrites from last few days of month to smaller last month', async () => {
freezeTime(new Date(2024, 4, 31))
const time = document.createElement('relative-time')
time.setAttribute('tense', 'past')
time.setAttribute('datetime', '2024-04-30T00:00:00Z')
await Promise.resolve()
assert.equal(time.shadowRoot.textContent, 'last month')
})

test('rewrites from last few days of month to smaller previous month', async () => {
freezeTime(new Date(2024, 4, 31))
const time = document.createElement('relative-time')
time.setAttribute('tense', 'past')
time.setAttribute('datetime', '2024-02-29T00:00:00Z')
await Promise.resolve()
assert.equal(time.shadowRoot.textContent, '3 months ago')
})

test('micro formats years', async () => {
const datetime = new Date()
datetime.setFullYear(datetime.getFullYear() - 10)
Expand Down

0 comments on commit 7db58b3

Please sign in to comment.