Cron expression builder

Minute · hour · day · month · weekday.

Try one
POSIX cron
0 5 * * * · UTC

Plain-English schedule

At 05:00 every day

Previewed as wall-clock time in UTC. The runtime must use the same timezone to agree.

Calculating upcoming runs…

Minute0

minute 0

Hour5

hour 5

Day of month*

every day of month

Month*

every month

Day of week*

every day of week

Deployment snippets
crontab
0 5 * * * /usr/local/bin/task
GitHub Actions
schedule:
  - cron: '0 5 * * *'
EventBridge
cron(0 5 ? * * *)
SyntaxValid
Next runs0
Shortest gap
Cadence

Cron Expression Builder

Write a cron expression and read it back in plain English, with the next eight executions listed in a timezone you choose. Three dialects are covered — POSIX cron, AWS EventBridge cron, and EventBridge rate — because the differences between them are exactly where scheduled jobs go wrong.

Dialects supported
3
Upcoming runs previewed
8
Timezones to preview in
8
Requests made
0

Step by step

How to use it

  1. 01Pick the dialect

    POSIX cron for Unix crontabs and most schedulers, AWS cron for EventBridge — which has a sixth field and different day-of-week semantics — or rate for the simple every-N-units case.

  2. 02Write the expression, or edit the fields

    Type the whole expression, or set minute, hour, day, month, and weekday individually. Each field is described as you edit it, so an unfamiliar value explains itself.

  3. 03Read it back in English

    The plain-language description is the check that matters. If it does not say what you meant, the expression is wrong regardless of whether it parses.

  4. 04Check the next runs in the right timezone

    Eight upcoming executions, rendered as wall-clock time in the zone you select. The runtime must be using the same zone for those times to be the ones you get.

Worked example

The two fields that mean 'or'

Day-of-month and day-of-week are the only cron fields that combine with OR rather than AND. It is the single most common cron bug, and it does not announce itself.

Given

Intent
the 1st, only if it is a Monday
Written
0 9 1 * 1
Actual
something else entirely

Where the OR bites

0 9 1 * 1     -> 09:00 on the 1st of the month
                 OR every Monday
                 roughly 5 runs a month, not 1

0 9 1 * *     -> 09:00 on the 1st. correct.
0 9 * * 1     -> 09:00 every Monday. correct.

restrict both only in the job itself:
  exit early unless today is a Monday
Expected runs
~1 per month
Actual runs
~5 per month
Fields combining
OR, not AND

Every other field intersects: minute AND hour AND month. Day-of-month and day-of-week union, so restricting both widens the schedule instead of narrowing it. There is no expression for 'the first Monday' in standard cron — you schedule the wider one and check the date inside the job. The upcoming-runs list is what makes this visible before it runs in production.

Before you deploy the schedule

What to know about cron

Timezone is the other classic outage

A crontab runs in the server's local zone unless something says otherwise, and containers usually mean UTC. A job set for 09:00 by a developer in Berlin fires at 10:00 or 11:00 their time depending on the season. Decide the zone deliberately and preview in it.

Daylight saving skips and repeats runs

In a zone that observes DST, a job scheduled at 02:30 does not run at all on the spring-forward day and can run twice in the autumn. Anything financial or idempotency-sensitive belongs in UTC, where no such hour exists.

AWS cron is not POSIX cron

EventBridge takes six fields including a year, requires ? in one of the two day fields, and numbers the days of the week differently. An expression copied from a crontab will be rejected or, worse, accepted with a different meaning.

Rate expressions are not clock-aligned

rate(1 hour) means one hour after the last run, not on the hour. Restart the schedule and the alignment moves. When the run must happen at a specific minute, cron is the only option.

Cron does not care whether the last run finished

It starts a new execution on schedule regardless. A job that occasionally takes longer than its interval will overlap itself, which is how a nightly report becomes six concurrent copies. Guard with a lock rather than assuming the schedule protects you.

The description is the review

Nobody reads 0 9 1 * 1 correctly at a glance, including the person who wrote it. Pasting the plain-English description into the pull request is a two-second check that catches the field-order and OR mistakes before they ship.

The judgement call

Which schedule expression?

The dialects are not interchangeable, and one of the common intents has no expression at all.

  • A Unix crontab or most schedulers

    POSIX cron

    Five fields, minute through weekday. The dialect nearly everything outside AWS speaks.

  • An EventBridge rule at a fixed time

    AWS cron

    Six fields with a year, and ? required in one of the day fields. Not interchangeable with POSIX.

  • Every N minutes, alignment unimportant

    rate()

    Simpler and harder to get wrong — as long as you do not need it to land on the hour.

  • Must run at exactly :00 past the hour

    cron, not rate

    Rate measures elapsed time from the last run, so it drifts off the clock after any restart.

  • The first Monday of the month

    Check inside the job

    Day-of-month and day-of-week are OR'd. Schedule every Monday and exit unless the date is under the 8th.

  • Anything time-sensitive across DST

    Use UTC

    Spring forward skips an hour and autumn repeats one. UTC has neither problem.

Reference

How the fields work

POSIX fields
minute hour day month weekday0–59, 0–23, 1–31, 1–12, 0–6 with Sunday as 0. Five fields, no year.
AWS fields
minute hour day month weekday yearSix fields, and one of the two day fields must be ? rather than *.
The OR rule
day-of-month OR day-of-weekEvery other field is AND'd. Setting both widens the schedule rather than narrowing it.
Operators
* , - /Any value, a list, a range, and a step. */15 in the minute field is every quarter hour.
rate()
Elapsed time, not clock timeMeasured from the previous run, so it does not stay aligned to the hour across restarts.
Timezone
Whatever the runtime usesUsually UTC in containers and server-local in a crontab. The preview is only right if the two agree.

FAQ

Questions, answered plainly

How do I write a cron expression?

Five fields — minute, hour, day of month, month, day of week — separated by spaces, with * meaning any value. Type it here and read the plain-English description back: if the sentence does not match your intent, the expression is wrong even though it parses.

Why does my job run more often than I expect?

Almost certainly the day-of-month and day-of-week fields. They combine with OR rather than AND, so 0 9 1 * 1 means the 1st of the month or any Monday — about five runs a month instead of one. Every other field intersects, which is why this catches everyone once.

What timezone does cron use?

Whatever the runtime is configured for — server-local for a traditional crontab, UTC in most containers and managed schedulers. Preview the upcoming runs in the zone your runtime actually uses; a mismatch is one of the most common causes of a job firing at the wrong hour.

How do I schedule the first Monday of the month?

You cannot, in standard cron. Because the day fields are OR'd there is no expression that intersects them. Schedule every Monday and have the job exit immediately unless the day of the month is under 8 — that check belongs in your code, not in the expression.

What is the difference between AWS cron and normal cron?

EventBridge uses six fields including a year, requires ? in one of the two day fields instead of *, and numbers the weekdays differently. A crontab expression pasted into EventBridge is either rejected or silently interpreted as a different schedule.

Should I use rate() or cron?

rate() is simpler and harder to get wrong when the exact minute does not matter, because it just measures elapsed time. Use cron whenever the run has to land at a specific clock time — rate schedules drift away from the hour after any restart or redeploy.

Parsing, description, and the upcoming-run preview all happen in your browser. Nothing is sent anywhere.