A cron expression is a string of 5 (or 6) fields that defines a recurring schedule for running automated tasks. It is the standard format used in Unix cron jobs, CI/CD pipelines, cloud schedulers (AWS EventBridge, GitHub Actions), and most backend job frameworks.
What does each field in a cron expression mean?
┌─────────── minute (0–59)
│ ┌───────── hour (0–23)
│ │ ┌─────── day of month (1–31)
│ │ │ ┌───── month (1–12 or JAN–DEC)
│ │ │ │ ┌─── day of week (0–6 or SUN–SAT, 0=Sunday)
│ │ │ │ │
* * * * *Some systems add a 6th field for seconds (Quartz, Spring) at the beginning, or a 6th year field at the end.
What do the special characters (* , - / L W #) do?
| Character | Name | Meaning |
|---|---|---|
| * | Wildcard | Every value in the field |
| , | List | Multiple values: 1,3,5 |
| - | Range | A range of values: 1-5 |
| / | Step | Every N values: */5 = every 5 minutes |
| L | Last | Last day of month or week (some implementations) |
| W | Weekday | Nearest weekday to given day (some implementations) |
| # | Nth | 3rd Monday = MON#3 (some implementations) |
What are common cron schedule examples?
* * * * *Every minute*/5 * * * *Every 5 minutes0 * * * *Every hour (at :00)0 */2 * * *Every 2 hours0 9 * * *Daily at 9:00 AM0 0 * * *Daily at midnight0 9 * * MON-FRIWeekdays at 9:00 AM0 9 * * 1Every Monday at 9:00 AM0 0 1 * *First day of every month at midnight0 0 1 1 *Once a year on January 1st at midnight30 8 * * 1-5Weekdays at 8:30 AM0 0,12 * * *Twice daily: midnight and noon0/30 * * * *Every 30 minutes (Quartz syntax)Can I use month and day-of-week names instead of numbers?
Months
| Number | Name |
|---|---|
| 1 | JAN |
| 2 | FEB |
| 3 | MAR |
| 4 | APR |
| 5 | MAY |
| 6 | JUN |
| 7 | JUL |
| 8 | AUG |
| 9 | SEP |
| 10 | OCT |
| 11 | NOV |
| 12 | DEC |
Days of Week
| Number | Name |
|---|---|
| 0 (or 7) | SUN |
| 1 | MON |
| 2 | TUE |
| 3 | WED |
| 4 | THU |
| 5 | FRI |
| 6 | SAT |
How do cron implementations differ across platforms?
0 and 7 as Sunday for day-of-week. Always check your platform's documentation.How do timezones affect cron schedules?
The schedule 0 9 * * * means "9 AM" — but in which timezone? The answer depends on where the cron daemon runs, not where you wrote the expression. A schedule that fires at 9 AM in your local editor can land at 1 AM in production if the host is set to UTC.
- System cron (Linux): reads the
TZenvironment variable, otherwise uses/etc/localtime. Inside Docker, the default is UTC unless the image setsTZor mounts/etc/localtime. - vixie/cronie: supports a
CRON_TZ=Europe/Stockholmline at the top of a crontab to pin the schedule to a named zone. - GitHub Actions: always UTC.
0 9 * * *fires at 09:00 UTC, which is 04:00 in New York during EST. There is no per-workflow timezone option. - AWS EventBridge: historic Rules use UTC only. EventBridge Scheduler (released 2022) accepts a
ScheduleExpressionTimezoneparameter, including DST-aware zones likeAmerica/New_York. - Daylight Saving Time: a job scheduled for 02:30 local can run twice on fall-back day or skip on spring-forward day. UTC sidesteps both.
For workflow-specific tips, see the GitHub Actions cheatsheet.
How do I debug a cron job that doesn't run?
Most failed cron jobs aren't broken cron expressions — they're environment, path, or permission problems. Walk through these checks in order:
- Confirm the entry is installed: run
crontab -las the user that owns the job. System-wide entries live in/etc/crontaband/etc/cron.d/*. - Check cron logs: on Debian/Ubuntu look at
/var/log/syslogfiltered withgrep CRON; on RHEL/CentOS check/var/log/cron; under systemd usejournalctl -u cronorjournalctl -u crond. - Cron has a minimal PATH: usually only
/usr/bin:/bin. Use absolute paths in commands or setPATH=...at the top of the crontab. - Capture stderr: append
>> /var/log/myjob.log 2>&1to the command, or setMAILTO=ops@example.comat the top of the crontab to receive failures by email. - End the line with a newline: entries without a trailing newline are silently ignored on some implementations.
- Validate the expression: paste it into the Cron Expression Parser to see the next 5 fire times. If they don't match what you expected, the bug is in the expression.
- Container caveats: Docker images often ship without a cron daemon, run with PID 1 not forking, and default to UTC. Use a sidecar scheduler or your platform's native scheduler (EventBridge, Cloud Scheduler, Kubernetes CronJob) instead of stuffing cron inside an app container.
References
- crontab(5) — Linux man page — the canonical 5-field syntax, environment variables, and operator semantics.
- AWS EventBridge cron expressions — 6-field format with the trailing year field, UTC default, and EventBridge-specific quirks like the
?wildcard. - GitHub Actions schedule trigger — POSIX 5-field cron, UTC only, with notes on shortest interval (5 minutes) and runner availability.
- Quartz CronTrigger tutorial — the 6/7-field Java/Spring dialect with seconds, year, and the
L W #operators. - crontab.guru — interactive editor that explains any 5-field expression in plain English.
Parse and explain any cron expression with the Cron Expression Parser tool, or grab copy-paste schedules from the Cron examples cheatsheet.