diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 20bebdd..26e8fd5 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -15,7 +15,7 @@ jobs: - uses: actions/checkout@v3 - uses: actions/setup-node@v3 with: - node-version: 18 + node-version: 22 registry-url: https://registry.npmjs.org/ cache: npm - run: npm install -g npm@latest @@ -29,15 +29,15 @@ jobs: NODE_AUTH_TOKEN: ${{secrets.npm_token}} publish-github: name: Publish to GitHub Packages - runs-on: ubuntu-latest - permissions: + runs-on: ubuntu-latest + permissions: contents: read packages: write steps: - uses: actions/checkout@v3 - uses: actions/setup-node@v3 with: - node-version: 18 + node-version: 22 registry-url: https://npm.pkg.github.com cache: npm scope: '@github' diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 20ee438..7a23343 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -14,7 +14,7 @@ jobs: - name: Use Node.js 18.x uses: actions/setup-node@v3 with: - node-version: 18.x + node-version: 22 - name: npm install, build, and test run: | npm it diff --git a/src/duration.ts b/src/duration.ts index 74cb017..58492b2 100644 --- a/src/duration.ts +++ b/src/duration.ts @@ -86,12 +86,21 @@ export class Duration { export function applyDuration(date: Date | number, duration: Duration): Date { const r = new Date(date) - r.setFullYear(r.getFullYear() + duration.years) - r.setMonth(r.getMonth() + duration.months) - r.setDate(r.getDate() + duration.weeks * 7 + duration.days) - r.setHours(r.getHours() + duration.hours) - r.setMinutes(r.getMinutes() + duration.minutes) - r.setSeconds(r.getSeconds() + duration.seconds) + if (duration.sign < 0) { + r.setUTCSeconds(r.getUTCSeconds() + duration.seconds) + r.setUTCMinutes(r.getUTCMinutes() + duration.minutes) + r.setUTCHours(r.getUTCHours() + duration.hours) + r.setUTCDate(r.getUTCDate() + duration.weeks * 7 + duration.days) + r.setUTCMonth(r.getUTCMonth() + duration.months) + r.setUTCFullYear(r.getUTCFullYear() + duration.years) + } else { + r.setUTCFullYear(r.getUTCFullYear() + duration.years) + r.setUTCMonth(r.getUTCMonth() + duration.months) + r.setUTCDate(r.getUTCDate() + duration.weeks * 7 + duration.days) + r.setUTCHours(r.getUTCHours() + duration.hours) + r.setUTCMinutes(r.getUTCMinutes() + duration.minutes) + r.setUTCSeconds(r.getUTCSeconds() + duration.seconds) + } return r } diff --git a/src/relative-time-element.ts b/src/relative-time-element.ts index 2130065..068183d 100644 --- a/src/relative-time-element.ts +++ b/src/relative-time-element.ts @@ -82,11 +82,12 @@ export class RelativeTimeElement extends HTMLElement implements Intl.DateTimeFor #updating: false | Promise = false get #lang() { - return ( - this.closest('[lang]')?.getAttribute('lang') || - this.ownerDocument.documentElement.getAttribute('lang') || - 'default' - ) + const lang = this.closest('[lang]')?.getAttribute('lang') || this.ownerDocument.documentElement.getAttribute('lang') + try { + return new Intl.Locale(lang ?? '').toString() + } catch { + return 'default' + } } #renderRoot: Node = this.shadowRoot ? this.shadowRoot : this.attachShadow ? this.attachShadow({mode: 'open'}) : this diff --git a/test/duration.ts b/test/duration.ts index 3b35600..ecb9e68 100644 --- a/test/duration.ts +++ b/test/duration.ts @@ -81,16 +81,19 @@ suite('duration', function () { }) suite('applyDuration', function () { - const referenceDate = '2022-10-21T16:48:44.104Z' const tests = new Set([ - {input: 'P4Y', expected: '2026-10-21T16:48:44.104Z'}, - {input: '-P4Y', expected: '2018-10-21T16:48:44.104Z'}, - {input: '-P3MT5M', expected: '2022-07-21T16:43:44.104Z'}, - {input: 'P1Y2M3DT4H5M6S', expected: '2023-12-24T20:53:50.104Z'}, - {input: 'P5W', expected: '2022-11-25T16:48:44.104Z'}, - {input: '-P5W', expected: '2022-09-16T16:48:44.104Z'}, + {referenceDate: '2022-10-21T16:48:44.104Z', input: 'P5W', expected: '2022-11-25T16:48:44.104Z'}, + {referenceDate: '2022-11-25T16:48:44.104Z', input: '-P5W', expected: '2022-10-21T16:48:44.104Z'}, + {referenceDate: '2022-07-21T16:43:44.104Z', input: 'P3MT5M', expected: '2022-10-21T16:48:44.104Z'}, + {referenceDate: '2022-10-21T16:48:44.104Z', input: '-P3MT5M', expected: '2022-07-21T16:43:44.104Z'}, + {referenceDate: '2022-10-21T16:48:44.104Z', input: 'P4Y', expected: '2026-10-21T16:48:44.104Z'}, + {referenceDate: '2026-10-21T16:48:44.104Z', input: '-P4Y', expected: '2022-10-21T16:48:44.104Z'}, + {referenceDate: '2022-10-21T16:48:44.104Z', input: 'P1Y2M3DT4H5M6S', expected: '2023-12-24T20:53:50.104Z'}, + {referenceDate: '2023-12-24T20:53:50.104Z', input: '-P1Y2M3DT4H5M6S', expected: '2022-10-21T16:48:44.104Z'}, + {referenceDate: '2023-08-15T00:00:00.000Z', input: 'P1Y3M25D', expected: '2024-12-10T00:00:00.000Z'}, + {referenceDate: '2024-12-10T00:00:00.000Z', input: '-P1Y3M25D', expected: '2023-08-15T00:00:00.000Z'}, ]) - for (const {input, expected} of tests) { + for (const {referenceDate, input, expected} of tests) { test(`${referenceDate} -> ${input} -> ${expected}`, () => { assert.equal(applyDuration(new Date(referenceDate), Duration.from(input))?.toISOString(), expected) }) diff --git a/test/relative-time.js b/test/relative-time.js index b00e592..c98a1ae 100644 --- a/test/relative-time.js +++ b/test/relative-time.js @@ -434,6 +434,17 @@ suite('relative-time', function () { }) } + test('renders correctly when given an invalid lang', async () => { + const now = new Date().toISOString() + + const element = document.createElement('relative-time') + element.setAttribute('datetime', now) + element.setAttribute('lang', 'does-not-exist') + + await Promise.resolve() + assert.equal(element.shadowRoot.textContent, 'now') + }) + suite('[tense=past]', function () { test('always uses relative dates', async () => { freezeTime(new Date(2033, 1, 1)) @@ -517,7 +528,7 @@ suite('relative-time', function () { time.setAttribute('datetime', datetime) time.setAttribute('format', 'micro') await Promise.resolve() - assert.equal(time.shadowRoot.textContent, '10y') + assert.equal(time.shadowRoot.textContent, '11y') }) test('micro formats future times', async () => {