Skip to content
cronpad
Schedules / Natural language schedules

Natural language schedules

cronpad understands schedules written in plain English, like every 15 minutes, every weekday at 6:30pm or second tuesday of every month at 9am. The parser is deterministic (no AI involved): the same text always means the same thing. It is converted to an RRULE, which is stored as the job’s canonical schedule and shown back to you in plain English.

Examples

Intervals

You writeFires
every 30 secondsEvery 30 s (subject to the minimum interval)
every 15 minutesEvery 15 minutes
every hour, hourly, every 1 hourEvery hour
every 6 hoursEvery 6 hours
every 10 minutes for 2 hoursEvery 10 minutes, stopping 2 hours after the start

Days and times

You writeFires
every day at 9am, daily at 09:0009:00 every day
every day at 9am and 6pm09:00 and 18:00 every day
every weekday at 6:30pm18:30 Monday–Friday
every weekend at 10am10:00 Saturday and Sunday
every monday and thursday at 10:0010:00 on Mondays and Thursdays
every 2 weeks on friday at noon12:00 every other Friday
every hour between 9am and 5pm on weekdays09:00, 10:00 … 17:00 Monday–Friday

Days of the month

You writeFires
second tuesday of every month at 9am09:00 on the 2nd Tuesday
last friday of the month at 5pm17:00 on the last Friday
last day of every month at 23:5923:59 on the 28th–31st, whichever is last
first weekday of the month00:00 on the first Monday–Friday
on the 1st and 15th of every month at 8am08:00 on the 1st and 15th
every 3 months on the 1st, quarterlyThe 1st of every third month
every year on march 31 at 10am10:00 every 31 March

Limits

You writeEffect
every day at 9am 10 timesFires 10 times, then the job is completed
every monday at 8am until 2027-01-01Stops after 1 January 2027

One-off

You writeFires once
in 20 minutes20 minutes after you save
tomorrow at 8am08:00 tomorrow in the job’s timezone
at 2026-12-25 07:00That moment in the job’s timezone

Grammar

Words are case-insensitive. Clauses after the frequency may appear in any order. Filler words (the, of, on, at, each, and, commas) are accepted wherever they read naturally.

schedule   := oneshot | recurring
oneshot    := "in" duration | "at"? datetime | relday "at" time
recurring  := frequency dayclause? timeclause? window? bound?
frequency  := "every" [N] unit | hourly | daily | weekly | monthly | quarterly | yearly
unit       := second(s) | minute(s) | hour(s) | day(s) | week(s) | month(s) | year(s)
dayclause  := weekday-list | ordinal weekday ["of" "every"? "month"] | ordinal "day" | monthday-list
              | "weekday" | "weekend"
timeclause := "at" time ("and" time)*
window     := "between" time "and" time | "from" time "to" time
bound      := N "times" | "until" date | "for" duration
ordinal    := first | 1st | second | 2nd | third | 3rd | fourth | 4th | fifth | 5th | last | second to last
time       := 9am | 9:30am | 09:30 | 21:00 | noon | midnight
relday     := today | tomorrow | weekday-name

Defaults

  • No time given for a day-based schedule → 00:00 in the job’s timezone.
  • every N days/weeks/months counts from the job’s start time (starts_at, or when you created it).
  • A month that doesn’t have the requested day (the 31st in April, the 5th Friday) is skipped, as in RRULE. Use last day of every month for month-end.

When parsing fails

The error points at the word it didn’t understand and, when it can, suggests a correction (tuesdy → tuesday). If a schedule is too unusual for the grammar, write it as cron, Quartz or RRULE.

Parsing limits and canonical form

Expressions are limited to 4096 UTF-8 bytes, recurrence intervals to 1,000,000 units, and occurrence counts to 100,000. These parser bounds keep invalid input and finite-count checks bounded. Relative durations accept positive decimal numbers with seconds, minutes, hours, days, or weeks; a day is 24 elapsed hours. Time windows include their endpoints and must not end before their start on the same day. Multiple times with different minute/second values, and partial-hour windows, compile to a union of RRULE lines so they do not introduce unintended cross-products of hours and minutes.