@burglekitt/gmt
Version:
Temporal-based date and time utilities with timezone support and polyfill integration
40 lines (39 loc) • 2.32 kB
JavaScript
import { calendarSystemOfZonedValue } from "./calendarValueOfZoned.js";
import { parseCalendarZonedValue } from "./calendarZonedString.js";
/**
* Parse two GMT ZonedDateTime values for calendar-unit arithmetic (diff, count, length,
* split-by-unit): measure in the endpoints' shared calendar when both match, fall back to
* Gregorian/ISO otherwise, rather than rejecting outright. The zoned sibling of
* `calendarDatePairPolicy.ts`'s `parseCalendarDatePairForArithmetic` (E5 decision D5).
*
* The fallback is MORE load-bearing here than in `plain/`, not less.
* `Temporal.PlainDate.prototype.until` throws across mismatched calendars only for date units;
* `Temporal.ZonedDateTime.prototype.until` throws for EVERY `largestUnit` — verified, including
* `"hour"` and `"nanosecond"`. Without this policy, `diffZoned(hebrewValue, islamicValue,
* "hours")` would return `null` for a question that has nothing to do with either calendar.
*
* **Consume the returned `a`/`b`, never the values you parsed them from.** The returned operands
* are already normalized to the resolved calendar, and every downstream use — including a
* `Temporal.Duration.prototype.total` `relativeTo` anchor — has to be the normalized one. Feeding
* a raw calendar-tagged operand to `relativeTo` while measuring in ISO does NOT throw; it returns
* a plausible-looking wrong number (verified: 12.586… where the correct ISO answer is 12.5666…
* and the correct Hebrew answer is 13), which no sanity check would catch.
*
* Throws if either value fails to parse as a valid GMT ZonedDateTime string — callers are
* expected to have already validated both values (e.g. via `isValidCalendarZonedDateTime`) before
* calling this, consistent with GMT's existing gate-then-parse-inside-try structure.
*/
export function parseCalendarZonedPairForArithmetic(aValue, bValue) {
const calendarA = calendarSystemOfZonedValue(aValue);
const calendarB = calendarSystemOfZonedValue(bValue);
const a = parseCalendarZonedValue(aValue);
const b = parseCalendarZonedValue(bValue);
if (calendarA && calendarB && calendarA === calendarB) {
return { calendar: calendarA, a, b };
}
return {
calendar: "gregorian",
a: a.withCalendar("iso8601"),
b: b.withCalendar("iso8601"),
};
}