From 0c800344d23a222a7b17c30d5c6dd7b00fa5b90d Mon Sep 17 00:00:00 2001 From: Michael Varrieur Date: Mon, 10 Oct 2022 10:26:02 -0400 Subject: [PATCH] Add custom selectUnit, use in relativeTime function (#14008) --- package.json | 1 - src/common/datetime/relative_time.ts | 2 +- src/common/util/select-unit.ts | 97 +++++++++++++++++++++++++++ test/common/datetime/relative_time.ts | 8 +++ yarn.lock | 10 --- 5 files changed, 106 insertions(+), 12 deletions(-) create mode 100644 src/common/util/select-unit.ts diff --git a/package.json b/package.json index 987792155e..2db10f8920 100644 --- a/package.json +++ b/package.json @@ -43,7 +43,6 @@ "@formatjs/intl-numberformat": "^7.2.5", "@formatjs/intl-pluralrules": "^4.1.5", "@formatjs/intl-relativetimeformat": "^9.3.2", - "@formatjs/intl-utils": "^3.8.4", "@fullcalendar/common": "5.9.0", "@fullcalendar/core": "5.9.0", "@fullcalendar/daygrid": "5.9.0", diff --git a/src/common/datetime/relative_time.ts b/src/common/datetime/relative_time.ts index 4b517c608d..1adc6b7973 100644 --- a/src/common/datetime/relative_time.ts +++ b/src/common/datetime/relative_time.ts @@ -1,7 +1,7 @@ -import { selectUnit } from "@formatjs/intl-utils"; import memoizeOne from "memoize-one"; import { FrontendLocaleData } from "../../data/translation"; import { polyfillsLoaded } from "../translations/localize"; +import { selectUnit } from "../util/select-unit"; if (__BUILD__ === "latest" && polyfillsLoaded) { await polyfillsLoaded; diff --git a/src/common/util/select-unit.ts b/src/common/util/select-unit.ts new file mode 100644 index 0000000000..e18845cd44 --- /dev/null +++ b/src/common/util/select-unit.ts @@ -0,0 +1,97 @@ +export type Unit = + | "second" + | "minute" + | "hour" + | "day" + | "week" + | "month" + | "quarter" + | "year"; + +const MS_PER_SECOND = 1e3; +const SECS_PER_MIN = 60; +const SECS_PER_HOUR = SECS_PER_MIN * 60; +const SECS_PER_DAY = SECS_PER_HOUR * 24; +const SECS_PER_WEEK = SECS_PER_DAY * 7; + +// Adapted from https://github.com/formatjs/formatjs/blob/186cef62f980ec66252ee232f438a42d0b51b9f9/packages/intl-utils/src/diff.ts +export function selectUnit( + from: Date | number, + to: Date | number = Date.now(), + thresholds: Partial = {} +): { value: number; unit: Unit } { + const resolvedThresholds: Thresholds = { + ...DEFAULT_THRESHOLDS, + ...(thresholds || {}), + }; + + const secs = (+from - +to) / MS_PER_SECOND; + if (Math.abs(secs) < resolvedThresholds.second) { + return { + value: Math.round(secs), + unit: "second", + }; + } + + const mins = secs / SECS_PER_MIN; + if (Math.abs(mins) < resolvedThresholds.minute) { + return { + value: Math.round(mins), + unit: "minute", + }; + } + + const hours = secs / SECS_PER_HOUR; + if (Math.abs(hours) < resolvedThresholds.hour) { + return { + value: Math.round(hours), + unit: "hour", + }; + } + + const days = secs / SECS_PER_DAY; + if (Math.abs(days) < resolvedThresholds.day) { + return { + value: Math.round(days), + unit: "day", + }; + } + + const weeks = secs / SECS_PER_WEEK; + if (Math.abs(weeks) < resolvedThresholds.week) { + return { + value: Math.round(weeks), + unit: "week", + }; + } + + const fromDate = new Date(from); + const toDate = new Date(to); + const years = fromDate.getFullYear() - toDate.getFullYear(); + const months = years * 12 + fromDate.getMonth() - toDate.getMonth(); + if (Math.round(Math.abs(months)) < resolvedThresholds.month) { + return { + value: Math.round(months), + unit: "month", + }; + } + + return { + value: Math.round(years), + unit: "year", + }; +} + +type Thresholds = Record< + "second" | "minute" | "hour" | "day" | "week" | "month", + number +>; + +export const DEFAULT_THRESHOLDS: Thresholds = { + second: 45, // seconds to minute + minute: 45, // minutes to hour + hour: 22, // hour to day + day: 5, // day to week + week: 4, // week to months + month: 11, // month to years +}; diff --git a/test/common/datetime/relative_time.ts b/test/common/datetime/relative_time.ts index 8bb0be7133..2e020e1ddc 100644 --- a/test/common/datetime/relative_time.ts +++ b/test/common/datetime/relative_time.ts @@ -112,4 +112,12 @@ describe("relativeTime", () => { "1 month" ); }); + + it("handles a jump between years", () => { + const inputdt = new Date("2021-12-29"); + const compare = new Date("2022-01-01"); + + assert.strictEqual(relativeTime(inputdt, locale, compare), "3 days ago"); + assert.strictEqual(relativeTime(inputdt, locale, compare, false), "3 days"); + }); }); diff --git a/yarn.lock b/yarn.lock index 6c3e5251be..5b3051dcaf 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1679,15 +1679,6 @@ __metadata: languageName: node linkType: hard -"@formatjs/intl-utils@npm:^3.8.4": - version: 3.8.4 - resolution: "@formatjs/intl-utils@npm:3.8.4" - dependencies: - emojis-list: ^3.0.0 - checksum: e38a98d391ec68d8abc4bb1824426bd804dfb022ce61be004459faec69f7843ddb3733bae8d0dce4aafbfafad59cb10e67fc21d22d62f68d98251ce0bce8e704 - languageName: node - linkType: hard - "@fullcalendar/common@npm:5.9.0, @fullcalendar/common@npm:~5.9.0": version: 5.9.0 resolution: "@fullcalendar/common@npm:5.9.0" @@ -8982,7 +8973,6 @@ fsevents@^1.2.7: "@formatjs/intl-numberformat": ^7.2.5 "@formatjs/intl-pluralrules": ^4.1.5 "@formatjs/intl-relativetimeformat": ^9.3.2 - "@formatjs/intl-utils": ^3.8.4 "@fullcalendar/common": 5.9.0 "@fullcalendar/core": 5.9.0 "@fullcalendar/daygrid": 5.9.0