From 936397bb2345470103715a9618b72d51ddd5522c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=AA=20Duy=20Quang?= Date: Tue, 31 Dec 2024 16:31:04 +0700 Subject: [PATCH] Reimplement duration rounding. --- src/duration.ts | 133 +++++------- src/relative-time-element.ts | 13 +- test/duration.ts | 386 +++++++++++++---------------------- test/relative-time.js | 30 +-- 4 files changed, 214 insertions(+), 348 deletions(-) diff --git a/src/duration.ts b/src/duration.ts index 74cb017..1cb5ff0 100644 --- a/src/duration.ts +++ b/src/duration.ts @@ -119,101 +119,68 @@ export function elapsedTime(date: Date, precision: Unit = 'second', now = Date.n ) } +const durationRoundingThresholds = [ + Infinity, // Year + 11, // Month + 28, // Day + 21, // Hour + 55, // Minute + 55, // Second + 900, // Millisecond +] + interface RoundingOpts { relativeTo: Date | number } export function roundToSingleUnit(duration: Duration, {relativeTo = Date.now()}: Partial = {}): Duration { - relativeTo = new Date(relativeTo) + return roundBalancedToSingleUnit( + // TODO: Remove the positive sign in `+relativeTo` after integrating the new `elapsedTime` implementation. + elapsedTime(applyDuration(new Date(relativeTo), duration), 'millisecond', +relativeTo), + ) +} + +export function roundBalancedToSingleUnit(duration: Duration): Duration { if (duration.blank) return duration const sign = duration.sign - let years = Math.abs(duration.years) - let months = Math.abs(duration.months) - let weeks = Math.abs(duration.weeks) - let days = Math.abs(duration.days) - let hours = Math.abs(duration.hours) - let minutes = Math.abs(duration.minutes) - let seconds = Math.abs(duration.seconds) - let milliseconds = Math.abs(duration.milliseconds) - - if (milliseconds >= 900) seconds += Math.round(milliseconds / 1000) - if (seconds || minutes || hours || days || weeks || months || years) { - milliseconds = 0 + const values = [ + Math.abs(duration.years), + Math.abs(duration.months), + Math.abs(duration.days), + Math.abs(duration.hours), + Math.abs(duration.minutes), + Math.abs(duration.seconds), + Math.abs(duration.milliseconds), + ] + let biggestUnitIndex = values.findIndex(v => v > 0) + const roundedLowerUnit = + biggestUnitIndex < values.length - 1 && + values[biggestUnitIndex + 1] >= durationRoundingThresholds[biggestUnitIndex + 1] + if (roundedLowerUnit) { + values[biggestUnitIndex] += 1 } - - if (seconds >= 55) minutes += Math.round(seconds / 60) - if (minutes || hours || days || weeks || months || years) seconds = 0 - - if (minutes >= 55) hours += Math.round(minutes / 60) - if (hours || days || weeks || months || years) minutes = 0 - - if (days && hours >= 12) days += Math.round(hours / 24) - if (!days && hours >= 21) days += Math.round(hours / 24) - if (days || weeks || months || years) hours = 0 - - // Resolve calendar dates - const currentYear = relativeTo.getFullYear() - 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 - 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)) + monthDateCorrection - const monthsDiff = Math.abs(yearDiff * 12 + monthDiff) - if (daysDiff < 27) { - if (days >= 6) { - weeks += Math.round(days / 7) - days = 0 - } else { - days = daysDiff - } - months = years = 0 - } else if (monthsDiff <= 11) { - months = monthsDiff - years = 0 - } else { - months = 0 - years = yearDiff * sign - } - if (months || years) days = 0 + if (values[biggestUnitIndex] >= durationRoundingThresholds[biggestUnitIndex]) { + --biggestUnitIndex + values[biggestUnitIndex] = 1 } - if (years) months = 0 - - if (weeks >= 4) months += Math.round(weeks / 4) - if (months || years) weeks = 0 - if (days && weeks && !months && !years) { - weeks += Math.round(days / 7) - days = 0 + for (let i = biggestUnitIndex + 1; i < values.length; ++i) { + values[i] = 0 } - - return new Duration( - years * sign, - months * sign, - weeks * sign, - days * sign, - hours * sign, - minutes * sign, - seconds * sign, - milliseconds * sign, - ) + if (biggestUnitIndex === 2 && values[2] >= 6) { + const weeks = Math.max(1, Math.floor((values[2] + (roundedLowerUnit ? 0 : 1)) / 7)) + if (weeks < 4) { + return new Duration(0, 0, weeks * sign) + } + values[biggestUnitIndex] = 0 + --biggestUnitIndex + values[biggestUnitIndex] = 1 + } + values[biggestUnitIndex] *= sign + values.splice(2, 0, 0) + return new Duration(...values) } -export function getRelativeTimeUnit( - duration: Duration, - opts?: Partial, -): [number, Intl.RelativeTimeFormatUnit] { - const rounded = roundToSingleUnit(duration, opts) +export function getRoundedRelativeTimeUnit(rounded: Duration): [number, Intl.RelativeTimeFormatUnit] { if (rounded.blank) return [0, 'second'] for (const unit of unitNames) { if (unit === 'millisecond') continue diff --git a/src/relative-time-element.ts b/src/relative-time-element.ts index 068183d..ad624a5 100644 --- a/src/relative-time-element.ts +++ b/src/relative-time-element.ts @@ -1,4 +1,12 @@ -import {Duration, elapsedTime, getRelativeTimeUnit, isDuration, roundToSingleUnit, Unit, unitNames} from './duration.js' +import { + Duration, + Unit, + elapsedTime, + getRoundedRelativeTimeUnit, + isDuration, + roundToSingleUnit, + unitNames, +} from './duration.js' const HTMLElement = globalThis.HTMLElement || (null as unknown as typeof window['HTMLElement']) export type DeprecatedFormat = 'auto' | 'micro' | 'elapsed' @@ -157,6 +165,7 @@ export class RelativeTimeElement extends HTMLElement implements Intl.DateTimeFor const tense = this.tense let empty = emptyDuration if (format === 'micro') { + // TODO: Switch to `roundBalancedToSingleUnit` after integrating the new `elapsedTime` implementation. duration = roundToSingleUnit(duration) empty = microEmptyDuration if ((this.tense === 'past' && duration.sign !== -1) || (this.tense === 'future' && duration.sign !== 1)) { @@ -180,7 +189,7 @@ export class RelativeTimeElement extends HTMLElement implements Intl.DateTimeFor const tense = this.tense if (tense === 'future' && duration.sign !== 1) duration = emptyDuration if (tense === 'past' && duration.sign !== -1) duration = emptyDuration - const [int, unit] = getRelativeTimeUnit(duration) + const [int, unit] = getRoundedRelativeTimeUnit(roundToSingleUnit(duration)) if (unit === 'second' && int < 10) { return relativeFormat.format(0, this.precision === 'millisecond' ? 'second' : this.precision) } diff --git a/test/duration.ts b/test/duration.ts index 3b35600..8aa90d6 100644 --- a/test/duration.ts +++ b/test/duration.ts @@ -1,5 +1,12 @@ import {assert} from '@open-wc/testing' -import {applyDuration, Duration, elapsedTime, getRelativeTimeUnit, roundToSingleUnit} from '../src/duration.ts' +import { + Duration, + applyDuration, + elapsedTime, + getRoundedRelativeTimeUnit, + roundBalancedToSingleUnit, + roundToSingleUnit, +} from '../src/duration.ts' import {Temporal} from '@js-temporal/polyfill' suite('duration', function () { @@ -228,94 +235,126 @@ suite('duration', function () { } }) - suite('roundToSingleUnit', function () { - const roundTests = new Set([ - ['PT20S', 'PT20S'], - ['PT31S', 'PT31S'], + suite('roundBalancedToSingleUnit', function () { + const roundTests = [ + ['PT0S', 'PT0S'], + ['PT1S', 'PT1S'], ['PT55S', 'PT1M'], + ['PT57S', 'PT1M'], + ['PT1M', 'PT1M'], + ['PT1M10S', 'PT1M'], + ['PT1M55S', 'PT2M'], + ['PT54M55S', 'PT1H'], + ['PT55M', 'PT1H'], + ['PT57M', 'PT1H'], ['PT1H', 'PT1H'], - ['PT1H14M', 'PT1H'], - ['PT1H29M', 'PT1H'], - ['PT1H31M', 'PT1H'], + ['PT1H10M', 'PT1H'], + ['PT1H54M55S', 'PT1H'], ['PT1H55M', 'PT2H'], - ['PT20H', 'PT20H'], - ['PT21H', 'P1D'], - ['P1DT20H', 'P2D'], - ['P1DT18H', 'P2D'], - ['P4D', 'P4D', {relativeTo: new Date('2023-07-01T00:00:00')}], - ['-P4D', '-P4D', {relativeTo: new Date('2023-07-01T00:00:00')}], - ['P6D', 'P1W', {relativeTo: new Date('2023-07-01T00:00:00')}], - ['-P6D', '-P1W', {relativeTo: new Date('2023-07-01T00:00:00')}], - ['P2W', 'P2W', {relativeTo: new Date('2023-07-01T00:00:00')}], - ['-P2W', '-P2W', {relativeTo: new Date('2023-07-01T00:00:00')}], - ['P3W3D', 'P3W', {relativeTo: new Date('2023-07-01T00:00:00')}], - ['-P3W3D', '-P3W', {relativeTo: new Date('2023-07-01T00:00:00')}], - ['P3W6D', 'P1M', {relativeTo: new Date('2023-07-01T00:00:00')}], - ['-P3W6D', '-P1M', {relativeTo: new Date('2023-07-01T00:00:00')}], - ['P21D', 'P3W', {relativeTo: new Date('2023-07-01T00:00:00')}], - ['-P21D', '-P3W', {relativeTo: new Date('2023-07-01T00:00:00')}], - ['P24D', 'P3W', {relativeTo: new Date('2023-07-01T00:00:00')}], - ['-P24D', '-P3W', {relativeTo: new Date('2023-07-01T00:00:00')}], - ['P24DT25H', 'P1M', {relativeTo: new Date('2023-07-01T00:00:00')}], - ['-P24DT25H', '-P1M', {relativeTo: new Date('2023-07-01T00:00:00')}], - ['P25D', 'P1M', {relativeTo: new Date('2023-07-01T00:00:00')}], - ['-P25D', '-P1M', {relativeTo: new Date('2023-07-01T00:00:00')}], - ['P1M1D', 'P1M', {relativeTo: new Date('2023-07-02T00:00:00')}], - ['-P1M1D', '-P1M', {relativeTo: new Date('2023-07-02T00:00:00')}], - ['P1M1D', 'P2M', {relativeTo: new Date('2023-07-31T00:00:00')}], - ['-P1M1D', '-P2M', {relativeTo: new Date('2023-07-01T00:00:00')}], - ['P1D', 'P1D', {relativeTo: new Date('2022-01-01T00:00:00Z')}], - ['-P1D', '-P1D', {relativeTo: new Date('2022-01-01T00:00:00Z')}], - ['P8M', 'P8M', {relativeTo: new Date('2022-01-01T00:00:00Z')}], - ['-P8M', '-P8M', {relativeTo: new Date('2022-10-01T00:00:00Z')}], - ['P9M', 'P9M', {relativeTo: new Date('2022-01-01T00:00:00Z')}], - ['-P9M', '-P9M', {relativeTo: new Date('2022-11-01T00:00:00Z')}], - ['P1M', 'P1M', {relativeTo: new Date('2023-12-01T00:00:00Z')}], - ['-P1M', '-P1M', {relativeTo: new Date('2023-01-01T00:00:00Z')}], - ['P1M15D', 'P1M', {relativeTo: new Date('2023-12-01T00:00:00Z')}], - ['-P1M15D', '-P2M', {relativeTo: new Date('2023-01-01T00:00:00Z')}], - ['P1M15D', 'P2M', {relativeTo: new Date('2023-01-18T00:00:00Z')}], - ['-P1M15D', '-P2M', {relativeTo: new Date('2023-01-01T00:00:00Z')}], - ['P1M15D', 'P2M', {relativeTo: new Date('2023-01-18T00:00:00Z')}], - ['-P18M', '-P2Y', {relativeTo: new Date('2023-01-01T00:00:00Z')}], - ['P18M', 'P2Y', {relativeTo: new Date('2023-12-01T00:00:00Z')}], - ['-P18M', '-P1Y', {relativeTo: new Date('2023-07-01T00:00:00Z')}], - ['P18M', 'P2Y', {relativeTo: new Date('2023-07-01T00:00:00Z')}], - ['-P18M', '-P1Y', {relativeTo: new Date('2023-08-01T00:00:00Z')}], - ['P18M', 'P1Y', {relativeTo: new Date('2023-03-01T00:00:00Z')}], - [ - '-P9M20DT25H', - '-P10M', - { - relativeTo: new Date('2023-11-12T00:00:00Z'), - }, - ], - ['P9M20DT25H', 'P10M', {relativeTo: new Date('2023-01-12T00:00:00Z')}], - ['P11M', 'P11M', {relativeTo: new Date('2022-11-01T00:00:00Z')}], - ['-P11M', '-P11M', {relativeTo: new Date('2022-11-01T00:00:00Z')}], - ['-P11M15D', '-P1Y', {relativeTo: new Date('2024-01-06T00:00:00')}], - ['P1Y4D', 'P1Y', {relativeTo: new Date('2022-11-01T00:00:00Z')}], - ['P1Y5M13D', 'P1Y', {relativeTo: new Date('2023-01-01T00:00:00Z')}], - ['P1Y5M15D', 'P1Y', {relativeTo: new Date('2023-01-01T00:00:00Z')}], - ['P1Y5M20D', 'P1Y', {relativeTo: new Date('2023-01-01T00:00:00Z')}], - ['P1Y10M', 'P2Y', {relativeTo: new Date('2022-11-01T00:00:00Z')}], - ['-P1Y10M', '-P1Y', {relativeTo: new Date('2022-11-01T00:00:00Z')}], - ['P1Y10M', 'P1Y', {relativeTo: new Date('2022-01-01T00:00:00Z')}], - ['-P1Y10M', '-P1Y', {relativeTo: new Date('2022-12-01T00:00:00Z')}], - [ - '-P1Y5M20D', - '-P2Y', - { - relativeTo: new Date('2022-01-01T00:00:00Z'), - }, - ], - ['-P27D', '-P27D', {relativeTo: new Date('2023-02-28T00:00:00Z')}], - ['-P27D', '-P1M', {relativeTo: new Date('2023-02-27T00:00:00Z')}], - ['P1Y2M1D', 'P2Y', {relativeTo: new Date('2022-12-31T12:00:00.000Z')}], - ['-P1Y8D', '-P1Y', {relativeTo: new Date('2024-01-11T12:00:00.000Z')}], - ['-P1Y7DT19H43M19S', '-P1Y', {relativeTo: new Date('2024-01-11T12:00:00.000Z')}], - ['-P1Y11D', '-P2Y', {relativeTo: new Date('2024-01-11T12:00:00.000Z')}], - ]) + ['PT20H54M55S', 'PT20H'], + ['PT20H55M', 'P1D'], + ['PT22H', 'P1D'], + ['P1D', 'P1D'], + ['P1DT10H', 'P1D'], + ['P1DT20H55M', 'P1D'], + ['P1DT21H', 'P2D'], + ['P5DT20H55M', 'P5D'], + ['P5DT21H', 'P1W'], + ['P6D', 'P1W'], + ['P7D', 'P1W'], + ['P12DT20H55M', 'P1W'], + ['P12DT21H', 'P1W'], + ['P13DT', 'P2W'], + ['P14DT', 'P2W'], + ['P26DT20H55M', 'P3W'], + ['P26DT21H', 'P3W'], + ['P27D', 'P1M'], + ['P28D', 'P1M'], + ['P30D', 'P1M'], + ['P1M', 'P1M'], + ['P1M27DT21H', 'P1M'], + ['P1M28D', 'P2M'], + ['P10M27DT21H', 'P10M'], + ['P10M28D', 'P1Y'], + ['P11M', 'P1Y'], + ['P1Y', 'P1Y'], + ['P1Y10M27D', 'P1Y'], + ['P1Y11M', 'P2Y'], + ['-PT1S', '-PT1S'], + ['-PT55S', '-PT1M'], + ['-PT57S', '-PT1M'], + ['-PT1M', '-PT1M'], + ['-PT1M10S', '-PT1M'], + ['-PT1M55S', '-PT2M'], + ['-PT54M55S', '-PT1H'], + ['-PT55M', '-PT1H'], + ['-PT57M', '-PT1H'], + ['-PT1H', '-PT1H'], + ['-PT1H10M', '-PT1H'], + ['-PT1H54M55S', '-PT1H'], + ['-PT1H55M', '-PT2H'], + ['-PT20H54M55S', '-PT20H'], + ['-PT20H55M', '-P1D'], + ['-PT22H', '-P1D'], + ['-P1D', '-P1D'], + ['-P1DT10H', '-P1D'], + ['-P1DT20H55M', '-P1D'], + ['-P1DT21H', '-P2D'], + ['-P5DT20H55M', '-P5D'], + ['-P5DT21H', '-P1W'], + ['-P6D', '-P1W'], + ['-P7D', '-P1W'], + ['-P12DT20H55M', '-P1W'], + ['-P12DT21H', '-P1W'], + ['-P13DT', '-P2W'], + ['-P14DT', '-P2W'], + ['-P26DT20H55M', '-P3W'], + ['-P26DT21H', '-P3W'], + ['-P27D', '-P1M'], + ['-P28D', '-P1M'], + ['-P30D', '-P1M'], + ['-P1M', '-P1M'], + ['-P1M27DT21H', '-P1M'], + ['-P1M28D', '-P2M'], + ['-P10M27DT21H', '-P10M'], + ['-P10M28D', '-P1Y'], + ['-P11M', '-P1Y'], + ['-P1Y', '-P1Y'], + ['-P1Y10M27D', '-P1Y'], + ['-P1Y11M', '-P2Y'], + ] + for (const [input, expected] of roundTests) { + test(`roundBalancedToSingleUnit(${input}) === ${expected}`, () => { + assert.deepEqual(roundBalancedToSingleUnit(Duration.from(input)), Duration.from(expected)) + }) + } + }) + + suite('roundToSingleUnit', function () { + const roundTests = [ + ['PT1S', 'PT1S'], + ['PT58S', 'PT1M'], + ['PT66S', 'PT1M'], + ['PT5M', 'PT5M'], + ['PT58M', 'PT1H'], + ['PT66M', 'PT1H'], + ['PT20H55M', 'P1D'], + ['PT32H', 'P1D'], + ['P5DT21H', 'P1W'], + ['P6D', 'P1W'], + ['P16D', 'P2W'], + ['P20D', 'P3W'], + ['P27D', 'P1M'], + ['P45D', 'P1M'], + // TODO: Change this to P1M27D after integrating the new `elapsedTime` implementation. + ['P1M20D', 'P1M'], + ['P5M', 'P5M'], + ['P10M28D', 'P1Y'], + ['P18M', 'P1Y'], + ['P3Y', 'P3Y'], + ['P2M28D', 'P3M', {relativeTo: new Date('2023-07-15T00:00:00Z')}], + ['-P2M28D', '-P3M', {relativeTo: new Date('2023-10-15T00:00:00Z')}], + ] for (const [input, expected, opts] of roundTests) { test(`roundToSingleUnit(${input}) === ${expected}`, () => { assert.deepEqual( @@ -333,168 +372,19 @@ suite('duration', function () { } }) - suite('getRelativeTimeUnit', function () { - const relativeTests = new Set([ - ['PT20S', [20, 'second']], - ['PT31S', [31, 'second']], - ['PT55S', [1, 'minute']], - ['PT1H', [1, 'hour']], - ['PT1H14M', [1, 'hour']], - ['PT1H29M', [1, 'hour']], - ['PT1H31M', [1, 'hour']], - ['PT1H55M', [2, 'hour']], - ['PT20H', [20, 'hour']], - ['PT21H', [1, 'day'], {relativeTo: '2023-01-15T00:00:00Z'}], - ['-PT21H', [-1, 'day'], {relativeTo: '2023-01-15T00:00:00Z'}], - ['P4D', [4, 'day'], {relativeTo: '2023-01-15T00:00:00Z'}], - ['-P4D', [-4, 'day'], {relativeTo: '2023-01-15T00:00:00Z'}], - ['P6D', [1, 'week'], {relativeTo: '2023-01-15T00:00:00Z'}], - ['-P6D', [-1, 'week'], {relativeTo: '2023-01-15T00:00:00Z'}], - ['P2W', [2, 'week'], {relativeTo: '2023-01-15T00:00:00Z'}], - ['-P2W', [-2, 'week'], {relativeTo: '2023-01-15T00:00:00Z'}], - ['P3W3D', [3, 'week'], {relativeTo: '2023-01-15T00:00:00Z'}], - ['-P3W3D', [-3, 'week'], {relativeTo: '2023-01-15T00:00:00Z'}], - ['P3W6D', [1, 'month'], {relativeTo: '2023-01-15T00:00:00Z'}], - ['-P3W6D', [-1, 'month'], {relativeTo: '2023-01-15T00:00:00Z'}], - ['P21D', [3, 'week'], {relativeTo: '2023-01-01T00:00:00Z'}], - ['-P21D', [-3, 'week'], {relativeTo: '2023-01-01T00:00:00Z'}], - ['P24D', [3, 'week'], {relativeTo: '2023-01-01T00:00:00Z'}], - ['-P24D', [-3, 'week'], {relativeTo: '2023-01-01T00:00:00Z'}], - ['P24DT25H', [1, 'month'], {relativeTo: '2023-01-15T00:00:00Z'}], - ['P25D', [1, 'month'], {relativeTo: '2023-01-15T00:00:00Z'}], - ['-P35D', [-1, 'month'], {relativeTo: '2023-02-07T22:22:57Z'}], - ['-P45D', [-1, 'month'], {relativeTo: '2023-02-17T22:22:57Z'}], - ['-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'], - { - relativeTo: new Date('2022-01-01T00:00:00Z'), - }, - ], - [ - '-P8M', - [-8, 'month'], - { - relativeTo: new Date('2022-12-01T00:00:00Z'), - }, - ], - [ - 'P9M', - [9, 'month'], - { - relativeTo: new Date('2022-01-01T00:00:00Z'), - }, - ], - [ - '-P9M', - [-9, 'month'], - { - relativeTo: new Date('2022-12-01T00:00:00Z'), - }, - ], - ['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'], - { - relativeTo: new Date('2022-01-01T00:00:00Z'), - }, - ], - [ - '-P9M20DT25H', - [-10, 'month'], - { - relativeTo: new Date('2022-12-01T00:00:00Z'), - }, - ], - [ - 'P9M24DT25H', - [9, 'month'], - { - relativeTo: new Date('2022-01-01T00:00:00Z'), - }, - ], - [ - '-P9M24DT25H', - [-10, 'month'], - { - relativeTo: new Date('2022-12-01T00:00:00Z'), - }, - ], - ['P11M', [11, 'month']], - ['P1Y4D', [1, 'year']], - [ - 'P1Y5M13D', - [1, 'year'], - { - relativeTo: new Date('2022-01-01T00:00:00Z'), - }, - ], - [ - '-P1Y5M13D', - [-1, 'year'], - { - relativeTo: new Date('2022-12-01T00:00:00Z'), - }, - ], - [ - 'P1Y5M15D', - [1, 'year'], - { - relativeTo: new Date('2022-01-01T00:00:00Z'), - }, - ], - [ - '-P1Y5M15D', - [-1, 'year'], - { - relativeTo: new Date('2022-12-01T00:00:00Z'), - }, - ], - [ - 'P1Y5M20D', - [2, 'year'], - { - relativeTo: new Date('2022-12-01T00:00:00Z'), - }, - ], - [ - '-P1Y5M20D', - [-2, 'year'], - { - relativeTo: new Date('2022-01-01T00:00:00Z'), - }, - ], - ['P1Y10M', [2, 'year'], {relativeTo: new Date('2022-12-01T00:00:00Z')}], - [ - '-P1Y10M', - [-2, 'year'], - { - relativeTo: new Date('2022-10-01T00:00:00Z'), - }, - ], - ]) - for (const [input, [val, unit], opts] of relativeTests) { - 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}${opts ? `, ${JSON.stringify(opts)}` : ''}) === [-${val}, ${unit}]`, () => { - assert.deepEqual( - getRelativeTimeUnit(Duration.from(`-${input}`), opts || {relativeTo: new Date('2023-07-01T00:00:00')}), - [-val, unit], - ) + suite('getRoundedRelativeTimeUnit', function () { + const relativeTests = [ + ['PT1S', [1, 'second']], + ['PT2M', [2, 'minute']], + ['PT3H', [3, 'hour']], + ['P4D', [4, 'day']], + ['P3W', [3, 'week']], + ['P2M', [2, 'month']], + ['P1Y', [1, 'year']], + ] + for (const [input, [val, unit]] of relativeTests) { + test(`getRoundedRelativeTimeUnit(${input}) === [${val}, ${unit}]`, () => { + assert.deepEqual(getRoundedRelativeTimeUnit(Duration.from(input)), [val, unit]) }) } }) diff --git a/test/relative-time.js b/test/relative-time.js index 0d13096..7797adb 100644 --- a/test/relative-time.js +++ b/test/relative-time.js @@ -452,7 +452,7 @@ suite('relative-time', function () { time.setAttribute('tense', 'past') time.setAttribute('datetime', '2023-01-01T00:00:00Z') await Promise.resolve() - assert.equal(time.shadowRoot.textContent, '11 years ago') + assert.equal(time.shadowRoot.textContent, '10 years ago') }) test('rewrites from now past datetime to minutes ago', async () => { @@ -499,7 +499,7 @@ suite('relative-time', function () { time.setAttribute('tense', 'past') time.setAttribute('datetime', '2023-06-01T00:00:00Z') await Promise.resolve() - assert.equal(time.shadowRoot.textContent, '4 months ago') + assert.equal(time.shadowRoot.textContent, '3 months ago') }) test('rewrites from last few days of month to smaller last month', async () => { @@ -1235,7 +1235,7 @@ suite('relative-time', function () { datetime: '2022-12-03T15:46:00.000Z', tense: 'future', format: 'relative', - expected: 'in 2 months', + expected: 'next month', }, { datetime: '2022-12-03T15:46:00.000Z', @@ -1827,7 +1827,7 @@ suite('relative-time', function () { }, { reference: '2023-03-23T12:03:00.000Z', - datetime: '2023-03-21T16:03:00.000Z', + datetime: '2023-03-21T15:03:00.000Z', format: 'relative', tense: 'past', expected: '2 days ago', @@ -1974,10 +1974,10 @@ suite('relative-time', function () { datetime: '2024-03-31T14:46:00.000Z', tense: 'future', format: 'micro', - expected: '2y', + expected: '1y', }, { - datetime: '2024-04-01T14:46:00.000Z', + datetime: '2024-09-22T14:46:00.000Z', tense: 'future', format: 'micro', expected: '2y', @@ -2230,13 +2230,13 @@ suite('relative-time', function () { datetime: '2024-03-31T14:46:00.000Z', tense: 'future', format: 'auto', - expected: 'in 2 years', + expected: 'next year', }, { datetime: '2024-04-01T14:46:00.000Z', tense: 'future', format: 'auto', - expected: 'in 2 years', + expected: 'next year', }, { datetime: '2022-10-24T15:46:00.000Z', @@ -2299,14 +2299,14 @@ suite('relative-time', function () { lang: 'en', tense: 'future', formatStyle: 'narrow', - expected: 'in 2 yr.', + expected: 'next yr.', }, { datetime: '2024-04-01T14:46:00.000Z', lang: 'en', tense: 'future', formatStyle: 'narrow', - expected: 'in 2 yr.', + expected: 'next yr.', }, // Dates in the future @@ -2488,18 +2488,18 @@ suite('relative-time', function () { datetime: '2024-03-01T12:00:00.000Z', tense: 'future', format: 'auto', - expected: 'in 2 years', + expected: 'next year', }, { reference: '2022-12-31T12:00:00.000Z', datetime: '2024-03-01T12:00:00.000Z', tense: 'future', format: 'micro', - expected: '2y', + expected: '1y', }, { reference: '2021-04-24T12:00:00.000Z', - datetime: '2023-02-01T12:00:00.000Z', + datetime: '2023-03-22T12:00:00.000Z', tense: 'future', format: 'micro', expected: '2y', @@ -2512,11 +2512,11 @@ suite('relative-time', function () { expected: '4 years ago', }, { - reference: '2024-12-04T00:00:00.000Z', + reference: '2024-11-14T00:00:00.000Z', datetime: '2024-01-16T00:00:00.000Z', tense: 'past', format: 'auto', - expected: '11 months ago', + expected: '10 months ago', }, ])