Cadence
Presets, raw cron expressions, and the one-hour floor.
A schedule's cadence is a five-field cron expression, evaluated in the schedule's timezone. The Cadence step of the New schedule wizard offers four presets and a Custom cron option. A preset is compiled to its expression on the server before the schedule is stored, so every stored schedule has an expression and none has a preset.
Presets¶
| Preset | Expression | Fires |
|---|---|---|
| Daily | 0 9 * * * |
every day at 09:00 |
| Weekly | 0 9 * * 1 |
Mondays at 09:00 |
| Monthly | 0 9 1 * * |
the 1st of each month at 09:00 |
| Quarterly | 0 9 1 */3 * |
1 January, 1 April, 1 July and 1 October at 09:00 |
All four fire at 09:00 in the schedule's timezone. The wizard starts with Weekly selected.
The preset name appears only inside the wizard, on the Cadence and
Review steps. Once the schedule is created, the Schedules list shows its
expression: a schedule created with Weekly is listed as 0 9 * * 1.
Custom cron¶
Custom cron opens a Cron expression field for a standard five-field
expression: minute, hour, day of month, month, day of week. Month and weekday
names such as JAN and MON are accepted. The server refuses an expression
that:
- does not have exactly five whitespace-separated fields, which rules out
macros such as
@dailyand six-field expressions with seconds; cronitercannot parse or cannot find a fire for โ an out-of-range value such as minute61, or a date that never occurs such as0 9 31 2 *;- fails the one-hour floor, below.
The one-hour floor¶
The server refuses an expression whose sampled fire times are less than one hour apart on the local clock. The check runs when a cadence is previewed, when a schedule is created, and when an existing schedule's expression or timezone is changed. It computes the expression's fire times in the schedule's timezone starting from 00:00 UTC on 1 January 2026, and measures the 200 gaps between the first 201 of them. A gap shorter than one hour is refused, and the server's response carries this message:
schedule fires more often than the 1:00:00 floor (observed a 0:30:00 gap); use at least an hourly cadence
| Expression | Result |
|---|---|
0 * * * * |
accepted โ hourly is exactly at the floor |
*/30 * * * * |
rejected, 0:30:00 gap |
0,30 9 * * * |
rejected, 0:30:00 gap |
An expression with two minute values less than an hour apart fires at both in the first hour it matches, so the sample sees that gap at once. Two properties of the check limit what else it sees:
- It compares wall-clock times. Fire times are subtracted as local times in the schedule's zone, not as elapsed time. The two differ across a daylight-saving change, and the check can be wrong in either direction there: Timezones and DST shows an expression it accepts that fires 30 minutes apart, and one it rejects with a gap of zero.
- Its sample is fixed. The sample always starts at 1 January 2026,
whatever the date the schedule is created, and ends at the 201st fire. For
0 9 * * *that is 20 July 2026. A gap that first appears after the end of the sample is not measured.
The preview¶
The Next 3 runs panel on the Cadence step shows what the server makes
of the cadence you have chosen. It sends the preset or expression and the
timezone to POST /api/schedules/preview 300 ms after you stop changing them,
and shows the compiled expression on a cron row, followed by the next three
fire times. Each time is labelled with, and shown in, the schedule's timezone.
If the server rejects the cadence, the panel shows an error instead of the
times.
Next stays disabled until the preview has come back without an error and Campaign name is filled in.
The preview counts from the moment it was requested. The schedule's first run time is computed again, from the moment you press Create schedule.
Next: Timezones and DST.
Last updated 2026-09-22