UNPKG

@burglekitt/gmt

Version:

Temporal-based date and time utilities with timezone support and polyfill integration

58 lines (57 loc) 2.38 kB
import { Temporal } from "@js-temporal/polyfill"; import { normalizeDateTime, resolveRelativeRounding } from "../../internal/index.js"; import { isValidDate } from "../validate/index.js"; const AUTO_UNITS = [ { unit: "day", maxDays: 7 }, { unit: "week", maxDays: 28 }, { unit: "month", maxDays: 365 }, { unit: "year", maxDays: Infinity }, ]; /** * Format the relative time between a plain date and a reference date. * * - Auto-picks the display unit (day/week/month/year) based on the distance, unless * `largestUnit` forces one. * - `roundingMethod` controls how the distance rounds to the display unit. * * @param value ISO date string to format * @param locale optional: BCP 47 locale tag * @param options optional: { style, numeric, largestUnit, roundingMethod, reference } * @returns the formatted relative-time string, or "" on invalid input * * @example formatRelativeDate("2026-01-15", "en-US", { reference: "2026-04-15" }) // "3 months ago" * @example formatRelativeDate(value, "en-US", { roundingMethod: "floor" }) // rounds toward the earlier boundary * @example formatRelativeDate("not-a-date") // "" */ export function formatRelativeDate(value, locale, options = {}) { if (!isValidDate(value)) return ""; if (options.reference !== undefined && !isValidDate(options.reference)) return ""; try { const target = Temporal.PlainDate.from(value); const reference = options.reference ? Temporal.PlainDate.from(options.reference) : Temporal.Now.plainDateISO(); const diff = target.since(reference); const absDays = Math.abs(diff.total("day")); const unit = options.largestUnit ?? AUTO_UNITS.find((t) => absDays < t.maxDays)?.unit ?? "year"; let amount; try { amount = resolveRelativeRounding(diff.total(unit), options.roundingMethod); } catch { // month/year are calendrical and need a relativeTo anchor amount = resolveRelativeRounding(diff.total({ unit, relativeTo: reference }), options.roundingMethod); } return normalizeDateTime(new Intl.RelativeTimeFormat(locale, { numeric: options.numeric ?? "auto", style: options.style ?? "long", }).format(amount, unit)); } catch { return ""; } }