Cron Expression Cheat Sheet: Every 5 Minutes, Hourly, Daily, and More
Cron is one of those tools that every developer eventually reaches for — and then spends the next ten minutes searching for the right syntax. The five-field format looks simple until you need something like "every weekday at 9am except the first of the month" and you realize the field ordering isn't quite what you remembered.
This guide is the reference you can actually bookmark. It covers the standard cron syntax, a full cheat sheet of common expressions, the special characters you need to know, and how AWS EventBridge and systemd timers differ from classic cron.
The 5 Fields
A standard cron expression has exactly five fields, separated by spaces:
┌───────── minute (0–59)
│ ┌─────── hour (0–23)
│ │ ┌───── day of month (1–31)
│ │ │ ┌─── month (1–12 or JAN–DEC)
│ │ │ │ ┌─ day of week (0–7 or SUN–SAT, where 0 and 7 both = Sunday)
│ │ │ │ │
* * * * *
A * in any field means "every valid value for this field."
Special Characters
| Character | Meaning | Example |
|---|---|---|
* |
Every value | * * * * * — every minute |
, |
List of values | 0 9,17 * * * — at 9am and 5pm |
- |
Range of values | 0 9-17 * * * — every hour from 9am to 5pm |
/ |
Step values | */5 * * * * — every 5 minutes |
@reboot |
On system start | @reboot /path/to/script |
@hourly |
Shorthand for 0 * * * * |
|
@daily |
Shorthand for 0 0 * * * |
|
@weekly |
Shorthand for 0 0 * * 0 |
|
@monthly |
Shorthand for 0 0 1 * * |
|
@yearly |
Shorthand for 0 0 1 1 * |
Full Cron Expression Cheat Sheet
High-Frequency Schedules
| Expression | Description |
|---|---|
* * * * * |
Every minute |
*/2 * * * * |
Every 2 minutes |
*/5 * * * * |
Every 5 minutes |
*/10 * * * * |
Every 10 minutes |
*/15 * * * * |
Every 15 minutes |
*/30 * * * * |
Every 30 minutes |
Hourly Schedules
| Expression | Description |
|---|---|
0 * * * * |
Every hour (at :00) |
30 * * * * |
Every hour at :30 |
0 */2 * * * |
Every 2 hours |
0 */4 * * * |
Every 4 hours |
0 */6 * * * |
Every 6 hours |
0 */12 * * * |
Every 12 hours (midnight and noon) |
Daily Schedules
| Expression | Description |
|---|---|
0 0 * * * |
Every day at midnight |
0 1 * * * |
Every day at 1am |
0 9 * * * |
Every day at 9am |
0 17 * * * |
Every day at 5pm |
0 9,17 * * * |
Daily at 9am and 5pm |
0 8-17 * * * |
Every hour from 8am to 5pm |
0 0 * * * |
Daily at midnight |
Weekly Schedules
| Expression | Description |
|---|---|
0 0 * * 0 |
Every Sunday at midnight |
0 0 * * 1 |
Every Monday at midnight |
0 9 * * 1 |
Every Monday at 9am |
0 9 * * 1-5 |
Every weekday (Mon–Fri) at 9am |
0 9 * * MON-FRI |
Same, using named days |
0 0 * * 6,0 |
Every weekend (Sat and Sun) at midnight |
0 9 * * 1,3,5 |
Monday, Wednesday, Friday at 9am |
Monthly Schedules
| Expression | Description |
|---|---|
0 0 1 * * |
First day of every month at midnight |
0 0 15 * * |
15th of every month at midnight |
0 0 L * * |
Last day of every month (non-standard, varies by implementation) |
0 9 1 * * |
First of the month at 9am |
0 0 1,15 * * |
1st and 15th of every month |
Quarterly and Annual Schedules
| Expression | Description |
|---|---|
0 0 1 */3 * |
First of every quarter (Jan, Apr, Jul, Oct) |
0 0 1 1 * |
January 1st at midnight (new year) |
0 0 1 1,7 * |
January 1st and July 1st |
0 0 1 * 1 |
First of the month OR every Monday (see gotcha below) |
Common Gotchas
The Day-of-Month + Day-of-Week OR Problem
This is the most frequently misunderstood behavior in cron. When you specify a value (not *) in both the day-of-month field and the day-of-week field, most cron implementations treat it as OR, not AND.
# This does NOT mean "the first Monday of the month"
0 9 1 * 1
# This fires on:
# - The 1st of every month at 9am, AND
# - Every Monday at 9am
There is no standard cron syntax for "the first Monday of the month." Some implementations (Quartz Scheduler, AWS EventBridge) support # for this purpose — 1#1 means "the first Monday." In plain cron, you typically work around this in the script itself with a date check.
Timezone Handling
Classic cron runs in the system timezone of the machine it's installed on. If your server is in UTC and your business logic assumes local time, you'll be off by hours. Solutions:
- Set the machine to UTC everywhere and convert in application logic
- Use
CRON_TZ=America/New_Yorkat the top of your crontab (supported in Vixie cron and most modern distributions) - Use a scheduling system that has first-class timezone support (Kubernetes CronJobs, AWS EventBridge)
Minute 0 vs Wildcard
0 * * * * means "at minute 0 of every hour" — i.e., once per hour. * * * * * means "every minute." Easy to confuse when you're editing an existing expression quickly.
AWS EventBridge Cron Syntax
AWS EventBridge (formerly CloudWatch Events) uses a 6-field cron expression with important differences from standard cron:
┌───────── minute (0–59)
│ ┌─────── hour (0–23)
│ │ ┌───── day of month (1–31, or ?)
│ │ │ ┌─── month (1–12 or JAN–DEC)
│ │ │ │ ┌─ day of week (1–7 or SUN–SAT, where 1=Sunday)
│ │ │ │ │ ┌─ year (1970–2199)
│ │ │ │ │ │
* * * * * *
Key differences:
- Year field is required (use
*for "every year") - Day-of-week numbering: 1 = Sunday, 2 = Monday ... 7 = Saturday (not 0–6 like standard cron)
- ? (question mark) must be used in either day-of-month OR day-of-week (not both) to indicate "no specific value"
- L is supported for "last" (last day of month, last weekday)
- # is supported:
2#1means "the first Monday of the month" - All times are UTC — no timezone configuration
# AWS EventBridge examples
cron(0/5 * * * ? *) # Every 5 minutes
cron(0 9 * * MON-FRI *) # Every weekday at 9am UTC
cron(0 0 1 * ? *) # First of every month at midnight UTC
cron(0 12 ? * 2 *) # Every Monday at noon UTC (2 = Monday in AWS)
systemd Timer Syntax
If you're running modern Linux, systemd timers are a powerful alternative to cron. They're defined in two files: a .service file for the command to run, and a .timer file for the schedule.
# /etc/systemd/system/my-job.timer
[Unit]
Description=Run my-job every 5 minutes
[Timer]
OnCalendar=*:0/5
Persistent=true
[Install]
WantedBy=timers.target
systemd uses a different time specification syntax called calendar events:
| systemd OnCalendar | Equivalent Cron |
|---|---|
*:0/5 |
*/5 * * * * |
hourly |
0 * * * * |
daily |
0 0 * * * |
weekly |
0 0 * * 0 |
monthly |
0 0 1 * * |
Mon *-*-* 09:00:00 |
0 9 * * 1 |
*-*-1 00:00:00 |
0 0 1 * * |
Check your timer with systemd-analyze calendar "Mon *-*-* 09:00:00" — it shows the next trigger times, which is invaluable for verification.
systemd timers also support Persistent=true, which catches up missed runs after the system was down — something standard cron doesn't handle.
Build Expressions Without Memorizing Syntax
The Cron Expression Generator on DevDecode lets you build any cron expression using dropdowns and plain-English inputs, then shows you the resulting expression and lists the next 10 run times. It's particularly useful when you need something non-obvious like "every 20 minutes between 8am and 6pm on weekdays."
For time-related work, the Unix Timestamp tool lets you convert between human-readable dates and Unix timestamps — useful when you're testing scheduled jobs and need to verify what time a given timestamp represents.