Skip to content

recurringWindows

recurringWindows(weekly: Partial<Record<IsoWeekday, LocalWindow[]>>, range: Interval, timeZone: string, optionsArg?: { disambiguation?: "compatible" | "earlier" | "later" | "reject" | undefined; }): Interval[]

Return the instants a weekly pattern of local windows is open inside range, read in timeZone: the primitive under operating hours, curfews and recurring crew windows.

  • weekly maps ISO weekdays (1 = Monday … 7 = Sunday) to LocalWindows of wall time. A window whose to is at or before its from wraps past midnight and belongs to the date it starts on: { from: "23:00", to: "06:00" } under 5 is Friday 23:00 to Saturday 06:00, and { from: "00:00", to: "00:00" } is the whole day. No holidays or overrides; see operatingIntervals for those.
  • Each window edge is a local wall time resolved with resolveLocal. An edge in a skipped spring-forward hour is shifted by the gap: forward, or back when it is read "earlier" (TC39 DisambiguatePossibleEpochNanoseconds), so in a zone that skips midnight a date’s early window can open on the previous local date, before the date’s own first instant; it still belongs to its own date.
  • A window “reaches the range” for "reject" when the widest span it could cover (its from read "earlier", its to read "later") overlaps range. A rejected window elsewhere does not matter.
  • Windows are elapsed time between their resolved edges, so the wall-clock length is not the real one on transition nights: in New York, 23:00–06:00 is 8 hours across the fall-back night and 6 across the spring-forward one, and 00:00–00:00 is 25 and 23 hours.
  • A window whose edges resolve to an empty or inverted span on a transition night — only a window shorter than the gap it straddles — is empty that day and left out.
  • The result is clipped to range (half-open), sorted, and merged where windows overlap or touch, so a run of whole-day windows is one interval. Endpoints are UTC instants ending in Z, except a clipped edge, which is range’s own string.
  • Local dates follow the zone’s real days: a date the zone deleted (Pacific/Apia skipped 2011-12-30) has no windows, and a date re-entered after a fall-back is counted once.
  • [] is both a legitimate result (closed throughout, or an empty range) and the sentinel.
  • Returns [] when weekly has a key other than "1"–"7" or a malformed window, when range is not a valid Interval, when timeZone is invalid, when disambiguation is not one of the four values, and when the range spans more than 10,000 local dates (about 27 years) counted from the date range.start falls on, rather than a truncated list.
  • Limit at an offset with seconds. The instant is placed in the offset’s whole-minute zone, moved by its seconds, and the moved instant must be inside Temporal’s range. So within the offset’s seconds (under a minute) of the first instant Temporal supports (-271821-04-20T00:00:00Z), for an offset west of UTC, this returns []. An offset to the minute has no such limit.
ParameterTypeDescription
weeklyPartial<Record<IsoWeekday, LocalWindow[]>>windows by ISO weekday, { 1: [{ from: "09:00", to: "17:00" }], … }
rangeInterval{ start, end } record of ISO 8601 instant strings to expand the pattern inside
timeZonestringIANA name or UTC offset the windows are read in: a time zone identifier (+05:30, +0530, -08) or a stored offset (±HH:MM[:SS], what getTimeZoneOffset returns)

optionsArg

How a window edge on a clock change is resolved

OptionTypeDefaultDescription
disambiguation?"compatible" | "earlier" | "later" | "reject" (Disambiguation)"compatible", Temporal’s default.How a window edge in a repeated or skipped local hour becomes an instant, as resolveLocal resolves it. "compatible" takes the earlier instant of a repeated fall-back hour and the later one of a skipped spring-forward hour, and "earlier" and "later" take that side in both cases. "reject" returns [] when a window with such an edge reaches the range.

sorted, merged { start, end } records of the open instants, or [] on invalid input

import { recurringWindows } from "@northguild/gmt/calendar/hours";
recurringWindows({ 1: [{ from: "09:00", to: "17:00" }] }, { start: "2024-06-10T00:00:00Z", end: "2024-06-11T00:00:00Z" }, "America/New_York") // [{ start: "2024-06-10T13:00:00Z", end: "2024-06-10T21:00:00Z" }]
output 

calendar/hours/recurringWindows.ts