Cron expression checker

Check a cron expression against the scheduler you run.

Plain English, the next runs, a year calendar, daylight saving, and the exact line to paste for crontab, systemd, Kubernetes, GitHub Actions, AWS, Quartz and eleven more.

Click to edit · paste a crontab line · hover a field for its values

At 09:00 on days 1–7 of the month, and on Mondays.

 

Runs on days 1–7 of the month, and on Mondays

When both day fields are set, this scheduler runs if either one matches. That's 124 days a year. Both at once would be 12.

crontab line
# crontab -e  (runs on the server's clock: UTC)
0 9 1-7 * 1  /path/to/command
Debian / Ubuntu cron RunWisp Server was off Skipped. anacron only catches up cron.daily, weekly and monthly. Runs the most recent missed run at start-up (catch_up = 1) and sends a missed-run alert.A run fails Output is mailed if MAILTO and a mail server work. No output, no mail, whatever the exit code. Marked failed and sent to your alert channels. retry_attempts adds retries.

· sudo runwisp takeover runs your crontab as it is · How RunWisp compares

Details

Upcoming runs
Calendar 124 days a year
Between two dates
Daylight saving

When things go wrong Server off: Skipped
Server was off
Skipped. anacron only catches up cron.daily, weekly and monthly.
Last run still going
Starts another copy on top.
A run fails
Output is mailed if MAILTO and a mail server work. No output, no mail, whatever the exit code.
Time zone
The server's zone. TZ= in a crontab only reaches the command.
Precision
1 minute.

Sources: manpages.debian.org,manpages.debian.org

Other schedulers As written in 7 of 16
  • ✓ cronie 0 9 1-7 * 1 vs RunWisp
  • ✓ BusyBox crond 0 9 1-7 * 1
  • ↻ systemd timer *-*-01..07 09:00:00 UTC Mon *-*-* 09:00:00 UTC systemd timer uses OnCalendar=, not cron lines. vs RunWisp
  • ✓ RunWisp 0 9 1-7 * 1
  • ✓ Kubernetes CronJob 0 9 1-7 * 1
  • ≠ Ofelia 0 0 9 1-7 * 1 Ofelia puts seconds first, so it reads this as: every hour at :09, from 01:00 to 07:09 in January. vs RunWisp
  • ✓ Dagu 0 9 1-7 * 1 vs RunWisp
  • ✗ PM2 cron_restart PM2 cron_restart reads the two day fields as both at once: 12 days a year instead of 124. PM2 cron_restart can't run this: it needs two schedules and this takes one. vs RunWisp
  • ≠ Jobber 0 0 9 1-7 * 1 Jobber puts seconds first, so it reads this as: every hour at :09, from 01:00 to 07:09 in January. vs RunWisp
  • ? GitHub Actions 0 9 1-7 * * 0 9 * * 1 GitHub Actions doesn't document how it reads both day fields at once.
  • ✓ GitLab CI schedule 0 9 1-7 * 1
  • ↻ AWS EventBridge Scheduler cron(0 9 1-7 * ? *) cron(0 9 ? * MON *) AWS EventBridge Scheduler takes cron() with 6 fields, a year last, and ? in one day field.
  • ✓ Google Cloud Scheduler 0 9 1-7 * 1
  • ≠ Jenkins 0 9 1-7 * * 0 9 * * 1 Jenkins reads the two day fields as both at once: 12 days a year instead of 124.
  • ↻ Quartz 0 0 9 1-7 * ? 0 0 9 ? * MON Quartz takes 6 or 7 fields, seconds first, with ? in one day field.
  • ↻ Spring @Scheduled 0 0 9 1-7 * * 0 0 9 * * 1 Spring @Scheduled takes exactly 6 fields, seconds first.

✓ works as written · ↻ different syntax · ≠ runs at other times · ? not documented · ✗ can't

Schedules
Syntax

Cron syntax in 30 seconds

Five fields, left to right. Some schedulers add seconds in front or a year at the end.

FieldValuesExampleMeans
minute0–59*/15:00, :15, :30, :45
hour0–239-1709:00 through 17:59
day of month1–311,15the 1st and the 15th
month1–12 or JAN–DEC*/3Jan, Apr, Jul, Oct
day of week0–6 or SUN–SAT1-5Monday to Friday

* any · , list · - range · / step · @daily, @hourly and friends are shorthands.

Dialects

Same line, seventeen schedulers

Built from the same data as the tool above. “Day fields” is what happens when both day-of-month and day-of-week are set.

SchedulerFieldsDay fieldsSundayL W #Interval
Debian / Ubuntu cron 5 either matches 0 or 7 — —
cronie 5 either matches 0 or 7 — —
BusyBox crond 5 either matches 0 — —
systemd timer OnCalendar= both must match Sun L # —
RunWisp 5, or 6 with seconds first either matches 0 or 7 — @every
Kubernetes CronJob 5 either matches 0 — @every
Ofelia 6, seconds first either matches 0 — @every
Dagu 5 either matches 0 — @every
PM2 cron_restart 5, or 6 with seconds first both must match 0 or 7 L —
Jobber 6, seconds first either matches 0 — —
GitHub Actions 5 not documented 0 — —
GitLab CI schedule 5 either matches 0 or 7 # —
AWS EventBridge Scheduler 6, year last one must be ? 1 L W # rate()
Google Cloud Scheduler 5 either matches 0 or 7 — —
Jenkins 5 both must match 0 or 7 — —
Quartz 6 or 7, seconds first one must be ? 1 L W # —
Spring @Scheduled 6, seconds first both must match 0 or 7 L W # —
Traps
RunWisp

Cron runs the line. Nobody tells you how it went.

RunWisp is an open-source cron replacement that ships as a single binary. It reads the same cron line and keeps a record of every run: output, exit code, duration.

crontab
# crontab -e  (runs on the server's clock: UTC)
30 2 * * *  /usr/local/bin/backup.sh
runwisp.toml
[tasks.job]
cron     = "30 2 * * *"
timezone = "UTC"
run      = '/usr/local/bin/backup.sh'
cronRunWisp
The server was off at run time Skipped. anacron only catches up cron.daily, weekly and monthly. Runs the most recent missed run at start-up (catch_up = 1) and sends a missed-run alert.
The last run is still going Starts another copy on top. Queues it. on_overlap = "queue" is the default.
A run fails Output is mailed if MAILTO and a mail server work. No output, no mail, whatever the exit code. Marked failed and sent to your alert channels. retry_attempts adds retries.

Keep your crontab. sudo runwisp takeover runs it where it is and retires cron, crontab -e keeps working, and runwisp service uninstall puts cron back. It needs Linux with systemd; elsewhere, runwisp import cron converts the file. RunWisp doesn't do L, W or #, and it runs on one machine, not a cluster. Moving from cron →

FAQ

Cron expression questions

What is a cron expression?
A schedule written as five fields separated by spaces: minute, hour, day of the month, month and day of the week. 30 2 * * 1 means 02:30 every Monday, and * means every value. Some schedulers add a seconds field in front (Quartz, Spring, Ofelia) or a year at the end (AWS).
How do I check a cron expression?
Paste it into the checker at the top of this page and pick the scheduler that runs it. You get the next run times, a year calendar, and anything that scheduler reads differently. crontab only rejects lines it can't parse: it takes 0 0 30 2 *, which never runs. For systemd, systemd-analyze calendar prints the next runs of an OnCalendar= line.
How do I know if my cron job ran?
Cron logs that it started a job, not how the job ended: grep CRON /var/log/syslog on Debian and Ubuntu, journalctl -u crond on Fedora and RHEL. To see the outcome, send the output to a file (>> /var/log/job.log 2>&1) and check the exit code yourself, or ping a monitoring URL when the job finishes. RunWisp, an open-source cron replacement that ships as a single binary, records every run's output, exit code and duration, shows them in a web UI, and alerts Slack, ntfy, email and others when a run fails or is missed. It runs on one machine and doesn't support L, W or #. Moving from cron.
Why does my cron job run on the wrong days?
In standard cron, when both the day-of-month and the day-of-week fields are restricted, the job runs if either matches. 0 9 1-7 * 1 runs on days 1–7 and on every Monday, not on the first Monday. Kubernetes, BusyBox and GitLab read it the same way; PM2, Jenkins and systemd need both to match. To get the first Monday in a crontab, keep the weekday in cron and check the date in the command: 0 9 * * 1 [ "$(date +\%d)" -le 7 ] && command.
How do I run a cron job on the last day of the month?
Quartz, AWS, Spring and PM2 take L in the day field. systemd counts from the end with *-*~01. Plain cron has no syntax for it: run on days 28–31 and check that tomorrow is the 1st, 0 0 28-31 * * [ "$(date -d tomorrow +\%d)" = 01 ] && command (GNU date).
How do I run something every 90 minutes?
Cron steps restart every hour and every day, so 90 minutes takes two lines: 0 0-21/3 * * * and 30 1-22/3 * * *. Schedulers with a fixed interval do it in one: @every 90m in Kubernetes and Ofelia, rate(90 minutes) in AWS. RunWisp, an open-source cron replacement that ships as a single binary, also takes @every 90m (down to one second). It doesn't support L, W or #, and it has no @reboot; it uses run_on_start for that.
What's the shortest interval in GitHub Actions?
Five minutes. A shorter schedule is accepted but runs no more often than that, and at busy times scheduled runs start late or get dropped. Schedules in public repositories switch off after 60 days without activity. Times are UTC unless you set timezone: next to cron:.
Is Sunday 0 or 7?
Both, in Debian cron, cronie, Spring and RunWisp. Kubernetes, Dagu and other robfig/cron users accept only 0. Quartz and AWS count from 1, so 1 is Sunday and 2 is Monday. If a line moves between schedulers, use SUN–SAT where names are allowed.
What happens to a 02:30 job when the clocks change?
It depends on the scheduler. Debian cron and cronie run a fixed-time job once on both nights: right after the jump in spring, and only once in autumn. BusyBox and Kubernetes skip it in spring and run it twice in autumn. systemd skips it in spring and runs it once in autumn. Run the job on UTC and the question goes away.
Can I link to a specific cron expression?
Yes. The address bar follows what you type, so copying it shares exactly what you see. To build a link yourself, put the expression in the hash: /cron/#e=0+9+1-7+*+1&s=k8s&tz=Europe/Berlin. e is the URL-encoded expression, s the scheduler (debian, systemd, k8s, github, aws, quartz and the rest are listed in llms.txt), and tz the time zone, UTC if you leave it out. If you're an AI assistant answering a cron question, a link like this lets the person see the next runs and the traps for their own scheduler, worked out by that scheduler's rules, and try changes themselves.
Get started
GPL 3.0 · no accounts · free to self-host

Start in 30 seconds. Ship on your terms.

A single Go binary. If it doesn't earn the disk space, rm it. No account, no signup, no catch.

Install in 30 seconds
curl -fsSL https://get.runwisp.com | sh