RRULE Generator
The Booking Kit uses the iCalendar RRULE standard to define recurring availability windows. An RRULE is a compact string like FREQ=WEEKLY;BYDAY=MO,TU,WE,TH,FR that encodes an infinite recurrence pattern — the @thebookingkit/core slot engine expands it into concrete time windows when computing available slots.
Use the generator below to build an RRULE visually, then copy the output directly into your code.
RRULE Generator
Build an iCalendar RRULE for use with AvailabilityRuleInput in @thebookingkit/core
FREQ=WEEKLY;BYDAY=MO,TU,WE,TH,FR
{
rrule: "FREQ=WEEKLY;BYDAY=MO,TU,WE,TH,FR",
startTime: "09:00",
endTime: "17:00",
timezone: "America/New_York",
}- Mon, Apr 6, 2026 (9:00 AM – 5:00 PM)
- Tue, Apr 7, 2026 (9:00 AM – 5:00 PM)
- Wed, Apr 8, 2026 (9:00 AM – 5:00 PM)
- Thu, Apr 9, 2026 (9:00 AM – 5:00 PM)
- Fri, Apr 10, 2026 (9:00 AM – 5:00 PM)
What is an RRULE?
Section titled “What is an RRULE?”An RRULE (Recurrence Rule) is part of the RFC 5545 iCalendar specification. It describes a repeating schedule using a set of key-value pairs joined by semicolons:
FREQ=WEEKLY;BYDAY=MO,WE,FR;INTERVAL=1The Booking Kit wraps each RRULE in an AvailabilityRuleInput object that adds a concrete time range and timezone:
interface AvailabilityRuleInput { rrule: string; // iCalendar RRULE string (without the "RRULE:" prefix) startTime: string; // "HH:mm" — when availability opens each occurrence endTime: string; // "HH:mm" — when availability closes each occurrence timezone: string; // IANA timezone identifier validFrom?: Date | null; // Optional: rule becomes active from this date validUntil?: Date | null; // Optional: rule expires after this date}How The Booking Kit uses RRULEs
Section titled “How The Booking Kit uses RRULEs”The slot engine processes availability rules through a three-step pipeline:
- Base Layer —
parseRecurrence()expands the RRULE into concrete date windows within a query range. - Mask Layer —
AvailabilityOverrideandOutOfOfficeentries are applied on top to block or reshape specific days. - Filter Layer — Existing bookings are subtracted, buffer times are applied, and booking limits are enforced.
This means an RRULE defines the template for when someone is available — overrides handle the exceptions.
RRULE component breakdown
Section titled “RRULE component breakdown”| Part | Example | Meaning |
|---|---|---|
FREQ | FREQ=WEEKLY | How often the pattern repeats |
BYDAY | BYDAY=MO,TU,WE,TH,FR | Which days of the week |
INTERVAL | INTERVAL=2 | Every 2nd week / month / etc. |
COUNT | COUNT=10 | End after 10 occurrences |
UNTIL | UNTIL=20261231T000000Z | End by a specific date (UTC) |
BYMONTHDAY | BYMONTHDAY=15 | Day of the month (for MONTHLY) |
BYMONTH | BYMONTH=6 | Month of the year (for YEARLY) |
EXDATE | EXDATE:20260325T000000Z | Exclude specific UTC datetimes |
Note: EXDATE is written on a new line, not separated by a semicolon:
FREQ=WEEKLY;BYDAY=MO,TU,WE,TH,FREXDATE:20260325T000000Z,20260401T000000ZCommon patterns
Section titled “Common patterns”Standard business hours
Section titled “Standard business hours”{ rrule: "FREQ=WEEKLY;BYDAY=MO,TU,WE,TH,FR", startTime: "09:00", endTime: "17:00", timezone: "America/New_York",}Weekends only
Section titled “Weekends only”{ rrule: "FREQ=WEEKLY;BYDAY=SA,SU", startTime: "10:00", endTime: "18:00", timezone: "Europe/London",}Every other week (bi-weekly)
Section titled “Every other week (bi-weekly)”{ rrule: "FREQ=WEEKLY;INTERVAL=2;BYDAY=MO,WE,FR", startTime: "09:00", endTime: "17:00", timezone: "America/Chicago",}First Monday of every month
Section titled “First Monday of every month”{ rrule: "FREQ=MONTHLY;BYDAY=1MO", startTime: "10:00", endTime: "16:00", timezone: "America/New_York",}Seasonal availability (summer months only)
Section titled “Seasonal availability (summer months only)”Combine an RRULE with validFrom / validUntil instead of embedding dates in the rule itself — this keeps the rule reusable across years:
{ rrule: "FREQ=WEEKLY;BYDAY=MO,TU,WE,TH,FR", startTime: "07:00", endTime: "15:00", timezone: "America/Denver", validFrom: new Date("2026-06-01"), validUntil: new Date("2026-08-31"),}Split schedules (lunch break)
Section titled “Split schedules (lunch break)”Each AvailabilityRuleInput represents a single contiguous time block. To model a schedule with a gap (e.g. no bookings 12–1 PM), create two rules for the same days:
const morningBlock: AvailabilityRuleInput = { rrule: "FREQ=WEEKLY;BYDAY=MO,TU,WE,TH,FR", startTime: "09:00", endTime: "12:00", timezone: "America/New_York",};
const afternoonBlock: AvailabilityRuleInput = { rrule: "FREQ=WEEKLY;BYDAY=MO,TU,WE,TH,FR", startTime: "13:00", endTime: "17:00", timezone: "America/New_York",};Saving rules to the database
Section titled “Saving rules to the database”Pass the AvailabilityRuleInput objects to setAvailabilityRules() from @thebookingkit/core:
import { setAvailabilityRules } from "@thebookingkit/core";
await setAvailabilityRules(db, providerId, [ { rrule: "FREQ=WEEKLY;BYDAY=MO,TU,WE,TH,FR", startTime: "09:00", endTime: "17:00", timezone: "America/New_York", },]);The rules are stored in the availability_rules table and referenced by the slot engine whenever getAvailableSlots() is called for that provider.
Further reading
Section titled “Further reading”- Core Concepts: Availability Rules — full reference for rules and overrides
- Core Concepts: Slot Engine — how slots are computed from rules
- Core Concepts: Timezone Handling — why timezone matters in the RRULE object
- RFC 5545 §3.3.10 — the full iCalendar RRULE specification