Skip to Content
Getting Started

timeslottr

timeslottr is a zero-dependency TypeScript library for interval arithmetic over calendar time. It turns working hours into bookable slots, subtracts already-booked events, and intersects multiple participants’ calendars to find the windows where everyone is free.

It’s the engine layer that scheduling products like Calendly and cal.com are built on — the interval math, without the calendar sync, storage, or UI.

Features

  • Slot generation. Produce fixed-duration slots from a daily range or a per-weekday Map, with a configurable step interval (slotIntervalMinutes for overlapping or spaced starts), leading/trailing buffers, excluded windows, edge alignment (start / end / center), and a maxSlots cap.
  • Availability math. subtract (availability − busy) and intersect (overlap across N participants) run as sort-then-sweep passes — O((n + m) log m) and O(total · log) — instead of the nested loops these features are usually hand-rolled with.
  • Timezone & DST correct. Built on the platform Intl.DateTimeFormat API, so a day that springs forward or falls back yields the right number of real slots. No dayjs, no date-fns, no IANA database in your bundle.
  • Half-open intervals. Every interval is [start, end). A slot ending at 10:00 does not collide with one starting at 10:00, which eliminates the off-by-one errors that silently corrupt bookings.
  • Typed and portable. Fully typed, dual ESM/CJS, zero runtime dependencies. Runs in Node, edge runtimes, and browsers.

timeslottr is an engine, not a booking product. It hands you Date-based interval results; calendar sync and storage stay yours.

Installation

npm install timeslottr

Requires Node.js ≥ 18.

Your first slots

Generate 30-minute slots for a single day, skipping a lunch break:

import { generateTimeslots } from 'timeslottr' const slots = generateTimeslots({ day: '2024-01-01', timezone: 'America/New_York', range: { start: '09:00', end: '17:00' }, slotDurationMinutes: 30, excludedWindows: [{ start: '12:00', end: '13:00' }], }) console.log(slots.length) // 14 slots: 9 to 12 and 1 to 5, every 30 minutes console.log(slots[0].start.toISOString())

Each slot is a Timeslot with an inclusive start, an exclusive end, and some metadata. Start and end are real Date objects.

Find a time that works for a team

Take a base schedule, remove what is already booked, and keep only the windows where everyone is free.

import { generateAvailableTimeslots } from 'timeslottr' const slots = generateAvailableTimeslots({ day: '2024-01-01', timezone: 'America/New_York', range: { start: '09:00', end: '17:00' }, slotDurationMinutes: 30, busy: [{ start: '12:00', end: '13:00' }], // already-booked participantsBusy: [ [{ start: '09:00', end: '10:00' }], // Alice [{ start: '16:00', end: '17:00' }], // Bob ], }) // → 30-min slots only where the host, Alice, and Bob are all free

Where to next

Last updated on