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 does the interval math that sits underneath a scheduling product like Calendly or cal.com. The calendar sync, storage, and UI stay yours.
What can you use it for?
- A booking page. Turn “Monday to Thursday, 9 to 5, 30-minute meetings” into the list of times a customer can click.
- Interview loops, where the slot has to work for the candidate and three interviewers at once.
- Appointments that need prep or cleanup time around them, using the before and after buffers.
- Room, court, and equipment reservations. Same interval math, different noun.
- Shift and on-call rotas built from a per-weekday schedule across a date range.
- Delivery and pickup windows, with a cap on how far ahead people can book so nobody reserves a slot six months out.
Features
- Slot generation. Split a working day into fixed-length slots, with per-weekday hours, buffers, breaks, and overlapping starts.
- Availability math. Remove the time that is already booked, then keep only the windows where everyone is free.
- Timezones and daylight saving. Handled with what Node and browsers already ship, so no date library and no timezone database in your bundle.
- Half-open intervals. A slot that ends at 10:00 does not collide with one that starts at 10:00, so adjacent slots never double-book.
- Typed and portable. Fully typed, no runtime dependencies, ES modules and CommonJS. Runs in Node, edge runtimes, and browsers.
Installation
npm
npm install timeslottrRequires 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 freeWhere to next
Last updated on