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, 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)

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 LayerparseRecurrence() expands the RRULE into concrete date windows within a query range.
  2. Mask LayerAvailabilityOverride 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.

PartExampleMeaning
FREQFREQ=WEEKLYHow often the pattern repeats
BYDAYBYDAY=MO,TU,WE,TH,FRWhich days of the week
INTERVALINTERVAL=2Every 2nd week / month / etc.
COUNTCOUNT=10End after 10 occurrences
UNTILUNTIL=20261231T000000ZEnd by a specific date (UTC)
BYMONTHDAYBYMONTHDAY=15Day of the month (for MONTHLY)
BYMONTHBYMONTH=6Month of the year (for YEARLY)
EXDATEEXDATE:20260325T000000ZExclude 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.