Skip to Content
GuideCore Concepts

Core Concepts

A few ideas are worth understanding before you go further: half-open intervals, the Timeslot shape, and how time zones are handled.

Half-open intervals [start, end)

Every range, slot, exclusion, and availability window is half-open. The start is inclusive and the end is exclusive.

import { contains, createTimeslot } from 'timeslottr' const slot = createTimeslot( new Date('2024-01-01T09:00:00Z'), new Date('2024-01-01T10:00:00Z'), ) contains(slot, new Date('2024-01-01T09:00:00Z')) // true (start is inclusive) contains(slot, new Date('2024-01-01T10:00:00Z')) // false (end is exclusive)

This is what stops adjacent slots from overlapping. A 9:00 to 10:00 slot and a 10:00 to 11:00 slot both touch 10:00, but the first one excludes its end, so they do not conflict. overlaps, subtract, and intersect all follow the same rule, so booked time that ends exactly when a slot begins does not block it.

The Timeslot shape

generateTimeslots and the other generators return Timeslot[]:

interface Timeslot { start: Date // inclusive end: Date // exclusive metadata?: { index: number // 0-based position in the result durationMinutes: number label?: string // from labelFormatter, if provided } }

start and end are real Date instants, stored as UTC. To send them over the wire, use timeslotToJSON and timeslotFromJSON. Plain JSON.stringify turns the dates into strings and will not parse them back into Date objects.

Timezones and DST

You can write a boundary as a time-only string ('09:00'), a full ISO string, a Date, or a { date, time } object. When you pass a timezone such as 'America/New_York', time-only boundaries are resolved in that zone and converted to the correct UTC instant. This runs on the platform Intl API, so there is no date library involved.

Daylight saving is handled for you. On a spring-forward day the 2:00 to 3:00 wall-clock hour does not exist, so a 00:00 to 06:00 range produces the right number of real slots:

const slots = generateTimeslots({ day: '2024-03-10', // US spring-forward timezone: 'America/New_York', range: { start: '00:00', end: '06:00' }, slotDurationMinutes: 30, }) slots.length // 10: six wall-clock hours, but only five real ones

Durations are measured in real elapsed time. Every 30-minute slot above is exactly 30 minutes long, including the one that spans the DST gap.

Time-only boundaries need a calendar date to anchor them. Pass day for a single day, or let generateDailyTimeslots set it per day. See the scheduling guide.

Last updated on