Cron Expression Explainer + Visualizer

Paste a cron expression — get a plain-English description, field-by-field breakdown, and the next 10 fire times in your local timezone or UTC. Supports the standard 5-field syntax plus @hourly/@daily/@weekly/@monthly/@yearly shorthands.

Developer Tools
ProDentim Sponsored
Quick examples:

The five fields of a cron expression

┌─────────── minute        (0-59)
│ ┌───────── hour          (0-23)
│ │ ┌─────── day of month  (1-31)
│ │ │ ┌───── month         (1-12 or JAN-DEC)
│ │ │ │ ┌─── day of week   (0-6, Sun=0; some systems also accept 7=Sun)
│ │ │ │ │
* * * * *

Each field accepts: a single value (5), a range (1-5), a list (1,3,5), a step (*/15, "every 15"), or a combination (0-30/5). The asterisk * means "any value". Most modern cron implementations also accept the shorthands @yearly, @monthly, @weekly, @daily, @hourly, and @reboot.

The day-of-month / day-of-week trap

The single most common cron bug: when both "day of month" and "day of week" are set to non-asterisk values, traditional cron treats them as OR, not AND. So 0 0 1 * 1 doesn't mean "the 1st of the month, only if it's a Monday" — it means "the 1st of every month, OR every Monday". Three jobs a month most of the time, more when those overlap.

To get AND semantics, keep one of the two fields as * and filter the other side in your script. Or use a scheduler that supports the AND interpretation explicitly (Quartz, AWS EventBridge, Cron Job Organizer in n8n, etc.).

Time zones

Cron runs in the local time zone of the server it's running on — unless the runtime explicitly says otherwise. This is fine for personal Linux boxes; it's a recurring footgun in cloud environments where the server's clock might be UTC even if you mentally compose schedules in your local time.

  • Linux crond / vixie-cron: uses the system's /etc/localtime. Set CRON_TZ=America/New_York at the top of a crontab to override per-file.
  • AWS EventBridge / CloudWatch Events: always UTC. No way to set a TZ in the expression itself.
  • GitHub Actions: always UTC. Schedule expression is evaluated in UTC regardless of where you live.
  • Kubernetes CronJob: respects the spec.timeZone field (introduced in 1.27). Without it, defaults to the kube-controller-manager's local time.
  • Node.js (node-cron): takes an optional timezone parameter; without it, the OS clock applies.

Daylight Saving Time: cron does not handle DST gracefully. A job scheduled for 2:30 AM during a spring-forward will be skipped (that time doesn't exist that day). During fall-back, it can run twice (the hour repeats). For DST-sensitive jobs, schedule in UTC and offset in your code.

Non-standard extensions you'll see in the wild

  • Seconds field — Quartz (Java) and some schedulers add a 6th field at the start for seconds, allowing sub-minute precision: */30 * * * * * = every 30 seconds. Linux cron has minute resolution only.
  • L for "last" — Quartz and AWS EventBridge accept L in the day-of-month field for "last day of the month", and in the day-of-week field for "last weekday".
  • W for nearest weekday — Quartz/AWS: 15W means "the weekday closest to the 15th".
  • # for nth weekday — Quartz/AWS: 2#3 means "the third Tuesday".
  • ? as "no specific value" — Quartz/AWS use ? instead of * in either the day-of-month or day-of-week field when the other is set, to avoid the OR-confusion described above.

This tool implements standard 5-field cron. If you paste a Quartz or AWS-EventBridge expression with L, W, or ?, it'll error. For those, use the platform's own validator (AWS Console has one built in).

Common pitfalls

  • Empty PATH. Cron jobs run in a minimal environment — $PATH is short, $HOME may not be set the way you expect. Use absolute paths to binaries (/usr/bin/python3, not python3), or set PATH at the top of the crontab.
  • Silent failures. Cron mails stderr by default — but only if there's a working local mailer. On modern cloud VMs there usually isn't. Redirect explicitly: command 2>&1 | logger -t myjob or to a logfile.
  • Overlapping runs. If your job takes longer than the interval, cron will start the next instance before the previous one finishes. Wrap with flock or a similar mutex: flock -n /tmp/myjob.lock command.
  • The job doesn't exist. service cron status returning "active" doesn't mean your job is running — your crontab entry might still be wrong. After crontab -e, check that crontab -l shows the entry. Check the system log (journalctl -u cron or /var/log/cron) for parse errors.
  • 0:00 vs 12:00 confusion. Cron uses 24-hour time. 0 12 * * * is noon, not midnight. Midnight is 0 0 * * *.
ProDentim Sponsored

Common use cases

Frequently asked questions

Day-of-month and day-of-week together — what happens?

Classic cron treats them as <strong>OR</strong>, not AND. <code>0 0 1 * 1</code> runs on the 1st of every month <strong>or</strong> every Monday — not "the 1st only if it's a Monday". To get AND behavior, keep one field as <code>*</code> and filter in your script.

Does it support the seconds field (Quartz / Spring)?

No — only standard 5-field cron. Quartz adds a 6th field for seconds (<code>* * * * * *</code>), which this tool doesn't parse. Same for Quartz extensions like <code>L</code>, <code>W</code>, <code>?</code>, <code>#</code>.

How are timezones handled?

Next-run times use your browser's local timezone by default. Toggle "show UTC" for the GMT-equivalent — useful for AWS EventBridge and GitHub Actions, which run in UTC regardless of your location.

Why does my schedule skip a run twice a year?

Daylight Saving Time. Cron doesn't handle DST transitions gracefully — a job at 2:30 AM during spring-forward simply doesn't run that day (the time doesn't exist); during fall-back, it can run twice. For DST-sensitive jobs, schedule in UTC.

Related tools