UNPKG

@burglekitt/gmt

Version:

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

56 lines (55 loc) 3.7 kB
import { durationUntilString, parseCalendarZonedPairForArithmetic, } from "../../internal/index.js"; import { isValidDateTimeDurationUnit } from "../../plain/validate/index.js"; import { isValidCalendarZonedDateTime } from "../validate/index.js"; /** * Return the difference between two zoned datetimes as an ISO 8601 duration string, * bridging to the `duration` namespace (see `parseDuration`, `normalizeDuration`). * * - Uses Temporal.ZonedDateTime.until with `largestUnit` set to `unit`, then `.toString()`. * - Converts both to UTC for consistent calculation, same as `diffZoned`. * - Accepts GMT calendar-annotated zoned strings, with the same shared-calendar-or-Gregorian- * fallback policy as `diffZoned` (E7's D5-zoned, issue #152). * - Unlike `diffZoned`, `unit` is a single unit (not an array) — an ISO duration string * already expresses a full multi-unit breakdown via `largestUnit` alone, so there's no * array-of-units overload here. * - Returns `""` for invalid input (negative diffs are valid and render with a leading `-`). * * `smallestUnit`, `roundingIncrement`, and `roundingMode` control optional rounding of the * underlying difference before it's rendered, per Temporal's DifferenceOptions — same as * `diffZoned`. `toStringSmallestUnit`, `fractionalSecondDigits`, and `toStringRoundingMode` * control the precision of the rendered string itself, per Temporal's ToStringPrecisionOptions * (mirroring `parseDuration`'s options) — kept separate from the `.until()` rounding options * above because both option sets have colliding `smallestUnit`/`roundingMode` keys with * different Temporal types. * * @param value1 zoned ISO 8601 datetime string (start), optionally calendar-annotated * @param value2 zoned ISO 8601 datetime string (end), optionally calendar-annotated * @param unit DateTimeDurationUnit to use as the duration's largestUnit * @param options optional: smallestUnit, roundingIncrement, roundingMode (.until() rounding); toStringSmallestUnit, fractionalSecondDigits, toStringRoundingMode (.toString() precision) * @returns ISO 8601 duration string, or "" on invalid input * * @example diffZonedAsDuration("2024-03-09T12:00:00-05:00[America/New_York]", "2024-03-11T12:00:00-04:00[America/New_York]", "days") // "P1DT23H" * @example diffZonedAsDuration("2028-01-01T00:00:00+00:00[UTC]", "2028-01-01T00:00:00+00:00[UTC]", "hours") // "PT0S" * @example diffZonedAsDuration("invalid", "2028-01-01T00:00:00+00:00[UTC]", "days") // "" * @example diffZonedAsDuration("5784-01-01T00:00:00-04:00[u-ca=hebrew][America/New_York]", "5785-01-01T00:00:00-04:00[u-ca=hebrew][America/New_York]", "months") // "P13M" (Hebrew leap year) * @example diffZonedAsDuration("2024-03-10T14:30:00-04:00[America/New_York][u-ca=hebrew]", "2024-03-11T14:30:00-04:00[America/New_York]", "days") // "" (Temporal's segment ordering is not GMT's grammar) */ export function diffZonedAsDuration(value1, value2, unit, options) { const validZonedDateTimes = isValidCalendarZonedDateTime(value1) && isValidCalendarZonedDateTime(value2); const validUnit = isValidDateTimeDurationUnit(unit); if (!validZonedDateTimes || !validUnit) { return ""; } try { // Calendar resolution before UTC normalization, and the normalization preserves the calendar // — see `diffZoned`'s equivalent comment. const { a, b } = parseCalendarZonedPairForArithmetic(value1, value2); const normalizedZdt1 = a.withTimeZone("UTC"); const normalizedZdt2 = b.withTimeZone("UTC"); return durationUntilString(normalizedZdt1, normalizedZdt2, unit, options); } catch { return ""; } }