@burglekitt/gmt
Version:
Temporal-based date and time utilities with timezone support and polyfill integration
40 lines (39 loc) • 3.34 kB
TypeScript
import type { Temporal } from "@js-temporal/polyfill";
import type { DateTimeDurationUnit, RoundingOptions } from "../../types/index.js";
/**
* Return the difference between two zoned datetimes measured in the given date-time unit.
*
* - Uses Temporal.ZonedDateTime.until to calculate difference.
* - Converts both to UTC for consistent calculation.
* - Supports single unit or array of units.
* - Accepts GMT calendar-annotated zoned strings (as produced by `convertZonedToCalendar`) —
* E7 (issue #152). When BOTH endpoints carry the same calendar tag, calendar units are measured
* in that calendar (a Hebrew leap year spans 13 month boundaries, not 14). When the tags
* mismatch, or either endpoint is a bare ISO string, the measurement falls back to
* Gregorian/ISO rather than returning the sentinel (E7's D5-zoned). That fallback is mandatory
* here, not a convenience: `Temporal.ZonedDateTime.prototype.until` throws across mismatched
* calendars for EVERY `largestUnit` — verified, including `"hour"` and `"nanosecond"` — so
* without it a purely time-unit question like "how many hours between these two moments" would
* return null just because the two strings named different calendars.
* - Returns null for invalid input.
*
* `smallestUnit`, `roundingIncrement`, and `roundingMode` control optional rounding of the result,
* per Temporal's DifferenceOptions — e.g. `{ smallestUnit: "hour", roundingMode: "halfExpand" }`
* rounds the difference to the nearest hour before extracting the requested unit.
* - When `units` is an array, `smallestUnit` must not be coarser than the largest unit in the
* array (e.g. `["day", "hour"]` with `smallestUnit: "week"`) — this combination is rejected by
* Temporal and returns null, same as other invalid input.
*
* @param value1 zoned ISO 8601 datetime string (start), optionally calendar-annotated
* @param value2 zoned ISO 8601 datetime string (end), optionally calendar-annotated
* @param units DateTimeDurationUnit | DateTimeDurationUnit[] to measure the difference
* @param options optional: smallestUnit, roundingIncrement, roundingMode (Temporal.DifferenceOptions rounding controls)
* @returns numeric difference in the requested unit, or null on invalid input
*
* @example diffZoned("2024-02-28T14:30:00+00:00[UTC]", "2024-03-01T15:30:00+00:00[UTC]", "days") // 2
* @example diffZoned("invalid", "2024-03-01T15:30:00+00:00[UTC]", "days") // null
* @example diffZoned("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") // 13 (Hebrew leap year; the ISO equivalent is 12)
* @example diffZoned("5784-01-01T00:00:00-04:00[u-ca=hebrew][America/New_York]", "1446-03-30T00:00:00-04:00[u-ca=islamic-tabular][America/New_York]", "hours") // measured in Gregorian/ISO (mismatched tags fall back rather than returning null)
* @example diffZoned("2024-03-10T14:30:00-04:00[America/New_York][u-ca=hebrew]", "2024-03-11T14:30:00-04:00[America/New_York]", "days") // null (Temporal's segment ordering is not GMT's grammar)
*/
export declare function diffZoned(value1: string, value2: string, units: DateTimeDurationUnit | DateTimeDurationUnit[], options?: RoundingOptions<Temporal.DateTimeUnit>): number | Record<DateTimeDurationUnit, number> | null;