Skip to content

diffZoned

diffZoned(value1: string, value2: string, units: any, options?: RoundingOptions<Temporal.DateTimeUnit>): number | Record<DateTimeDurationUnit, number>
import { diffZoned } from "@northguild/gmt/zoned/calculate";

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. &#123; smallestUnit: "hour", roundingMode: "halfExpand" &#125; 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.
Parameter Type Description
value1 string zoned ISO 8601 datetime string (start), optionally calendar-annotated
value2 string zoned ISO 8601 datetime string (end), optionally calendar-annotated
units any DateTimeDurationUnit | DateTimeDurationUnit[] to measure the difference
options RoundingOptions&lt;Temporal.DateTimeUnit&gt; optional: smallestUnit, roundingIncrement, roundingMode (Temporal.DifferenceOptions rounding controls)

numeric difference in the requested unit, or null on invalid input

diffZoned("2024-02-28T14:30:00+00:00[UTC]", "2024-03-01T15:30:00+00:00[UTC]", "days") // 2
diffZoned("invalid", "2024-03-01T15:30:00+00:00[UTC]", "days") // null
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)
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)
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)

zoned/calculate/diffZoned.ts