Skip to content

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

Days of Week
RRULE String
FREQ=WEEKLY;BYDAY=MO,TU,WE,TH,FR
AvailabilityRuleInput
{
  rrule: "FREQ=WEEKLY;BYDAY=MO,TU,WE,TH,FR",
  startTime: "09:00",
  endTime: "17:00",
  timezone: "America/New_York",
}
Human-Readable Description
Every week on Monday, Tuesday, Wednesday, Thursday, and Friday, from 9:00 AM to 5:00 PM.
Next 5 Occurrences
  • Mon, Oct 12, 2026 (9:00 AM – 5:00 PM)
  • Tue, Oct 13, 2026 (9:00 AM – 5:00 PM)
  • Wed, Oct 14, 2026 (9:00 AM – 5:00 PM)
  • Thu, Oct 15, 2026 (9:00 AM – 5:00 PM)
  • Fri, Oct 16, 2026 (9:00 AM – 5:00 PM)

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=1

The 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
}

The slot engine processes availability rules through a three-step pipeline:

  1. Base Layer — parseRecurrence() expands the RRULE into concrete date windows within a query range.
  2. Mask Layer — AvailabilityOverride and OutOfOffice entries are applied on top to block or reshape specific days.
  3. 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.

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,FR
EXDATE:20260325T000000Z,20260401T000000Z
{
rrule: "FREQ=WEEKLY;BYDAY=MO,TU,WE,TH,FR",
startTime: "09:00",
endTime: "17:00",
timezone: "America/New_York",
}
{
rrule: "FREQ=WEEKLY;BYDAY=SA,SU",
startTime: "10:00",
endTime: "18:00",
timezone: "Europe/London",
}
{
rrule: "FREQ=WEEKLY;INTERVAL=2;BYDAY=MO,WE,FR",
startTime: "09:00",
endTime: "17:00",
timezone: "America/Chicago",
}
{
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"),
}

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",
};

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.