RRStack computes all coverage in the rule’s IANA time zone and uses Luxon for duration arithmetic. This page covers helper functions for converting between “wall‑clock” values in a zone and epoch values, as well as DST semantics.
import {
wallTimeToEpoch,
dateOnlyToEpoch,
epochToWallDate,
RRStack,
} from '@karmaniverous/rrstack';
const tz = RRStack.asTimeZoneId('Europe/Paris');
// Interpret Date’s UTC Y/M/D/H/M/S as a local wall time in `tz`.
const wall = new Date(Date.UTC(2025, 6, 20, 9, 0, 0)); // "09:00" floating time-of-day
const tMs = wallTimeToEpoch(wall, tz, 'ms');
// Midnight local (date-only clamp)
const dateOnly = new Date(Date.UTC(2025, 6, 20, 0, 0, 0));
const midnight = dateOnlyToEpoch(dateOnly, tz, 'ms');
// Floating Date from epoch (UTC fields == local clock fields in tz)
const floater = epochToWallDate(tMs, tz, 'ms');
// wallTimeToEpoch(floater, tz, 'ms') === tMs
RangeError('Invalid Date') for invalid Date.RangeError('Invalid time zone') for unrecognized IANA zone.RangeError('Invalid time unit') for invalid unit.'s' mode, returns integer seconds (truncation for conversions). Occurrence ends elsewhere round up (see below).[start, end).'s'): occurrence end times are rounded up to the next second to avoid boundary false negatives.'ms': millisecond precision.'s': integer seconds (truncation).const s = new RRStack({ timezone: 'UTC' });
s.formatInstant(Date.UTC(2024, 0, 2, 5, 30, 0)); // '2024-01-02T05:30:00Z'
// Custom format & locale (Luxon)
s.formatInstant(Date.UTC(2024, 0, 2, 5, 30, 0), { format: 'yyyy-LL-dd HH:mm' });
// '2024-01-02 05:30'
dateOnlyToEpoch(selectedDate, stack.timezone, unit) to get local midnight in the rule’s zone.stack.formatInstant(t, { format }) for previews in the stack’s timezone.