# RRULE and one-off schedules

An RRULE is the recurrence format from the iCalendar standard (RFC 5545), used by calendar apps. It's the most expressive format cronpad supports, and every natural-language schedule is stored as one. A one-off schedule fires exactly once and then marks the job `completed`.

## RRULE

Write the rule without the `RRULE:` prefix. The start (`DTSTART`) is the job's `starts_at`, or its creation time, in the job's timezone.

| Rule | Fires |
|---|---|
| `FREQ=DAILY;BYHOUR=9;BYMINUTE=0;BYSECOND=0` | 09:00 every day |
| `FREQ=WEEKLY;BYDAY=MO,WE,FR;BYHOUR=7;BYMINUTE=30` | 07:30 Monday, Wednesday, Friday |
| `FREQ=WEEKLY;INTERVAL=2;BYDAY=FR;BYHOUR=12` | 12:00 every other Friday |
| `FREQ=MONTHLY;BYDAY=2TU;BYHOUR=9;BYMINUTE=0` | 09:00 on the second Tuesday |
| `FREQ=MONTHLY;BYDAY=-1FR;BYHOUR=17;BYMINUTE=0` | 17:00 on the last Friday |
| `FREQ=MONTHLY;BYMONTHDAY=-1;BYHOUR=23;BYMINUTE=59` | 23:59 on the last day of the month |
| `FREQ=MONTHLY;BYDAY=MO,TU,WE,TH,FR;BYSETPOS=-1` | The last weekday of the month |
| `FREQ=MONTHLY;BYDAY=FR;BYMONTHDAY=13` | Every Friday the 13th |
| `FREQ=YEARLY;BYMONTH=3;BYMONTHDAY=31;BYHOUR=10` | 10:00 every 31 March |
| `FREQ=HOURLY;BYHOUR=9,10,11,12,13,14,15,16,17;BYDAY=MO,TU,WE,TH,FR` | Hourly 09:00–17:00 on weekdays |
| `FREQ=DAILY;COUNT=10` | Daily, 10 times |
| `FREQ=DAILY;UNTIL=20270101T000000Z` | Daily until 1 January 2027 |

Supported parts: `FREQ` (`SECONDLY` to `YEARLY`), `INTERVAL`, `COUNT`, `UNTIL`, `BYSECOND`, `BYMINUTE`, `BYHOUR`, `BYDAY`, `BYMONTHDAY`, `BYYEARDAY`, `BYWEEKNO`, `BYMONTH`, `BYSETPOS`, `WKST`.

`FREQ` is required. Expressions are limited to 4096 UTF-8 bytes, `INTERVAL` to
1,000,000, and `COUNT` to 100,000. RRULE `COUNT` includes `DTSTART` when it
matches; querying strictly after that instant omits that already-counted occurrence.
A monthly rule requesting the 31st skips months without a 31st, and a yearly
February 29 rule skips non-leap years, including century years such as 2100.

## One-off

Use an RFC 3339 timestamp, or natural language:

| Schedule | Fires once at |
|---|---|
| `2026-12-25T07:00:00+05:30` | That exact instant |
| `in 20 minutes` | 20 minutes after the job is saved |
| `tomorrow at 8am` | 08:00 tomorrow in the job's timezone |
| `at 2026-12-25 07:00` | That wall-clock time in the job's timezone |

A one-off time in the past is rejected when you save the job. After it fires (including retries), the job's state becomes `completed`; its run stays in history.