Cron is the time-based job scheduler in Unix-like systems. Whether you're scheduling backups, sending reports, or running maintenance tasks, understanding cron expressions is essential.
What is Cron?
Cron runs scheduled commands at specified times. The schedule is defined using a cron expression—a string of five (or six) fields representing when to run.
A cron job entry looks like:
30 4 * * * /path/to/script.sh
This runs script.sh at 4:30 AM every day.
Cron Expression Format
The standard cron expression has five fields:
┌───────────── minute (0 - 59)
│ ┌───────────── hour (0 - 23)
│ │ ┌───────────── day of month (1 - 31)
│ │ │ ┌───────────── month (1 - 12)
│ │ │ │ ┌───────────── day of week (0 - 6) (Sunday = 0)
│ │ │ │ │
* * * * * command
Each field accepts:
- A specific value:
5 - A range:
1-5 - A list:
1,3,5 - A step:
*/15(every 15) - An asterisk:
*(any value)
Minutes, Hours, Days, Months, Weekdays
Minutes (0-59)
0 * * * * # At minute 0 (top of every hour)
30 * * * * # At minute 30
*/15 * * * * # Every 15 minutes (0, 15, 30, 45)
Hours (0-23)
0 9 * * * # At 9:00 AM
0 0 * * * # At midnight (0:00)
0 */2 * * * # Every 2 hours
0 9-17 * * * # Every hour from 9 AM to 5 PM
Day of Month (1-31)
0 0 1 * * # First day of every month
0 0 15 * * # 15th of every month
0 0 1,15 * * # 1st and 15th of every month
Month (1-12 or JAN-DEC)
0 0 1 1 * # January 1st
0 0 1 */3 * # First day of every quarter
0 0 1 6,12 * # June 1st and December 1st
Day of Week (0-6 or SUN-SAT)
0 0 * * 0 # Every Sunday
0 0 * * 1-5 # Monday through Friday
0 0 * * 6,0 # Weekends (Saturday and Sunday)
Special Characters
Asterisk (*) - Any Value
* * * * * # Every minute of every hour of every day
0 * * * * # Every hour (at minute 0)
Slash (/) - Step Values
*/5 * * * * # Every 5 minutes
0 */3 * * * # Every 3 hours
0 0 */2 * * # Every 2 days
Dash (-) - Ranges
0 9-17 * * * # Every hour from 9 to 17 (9 AM - 5 PM)
0 0 * * 1-5 # Monday through Friday
Comma (,) - Lists
0 0,12 * * * # Midnight and noon
0 0 1,15 * * # 1st and 15th
0 0 * * 0,3,6 # Sunday, Wednesday, Saturday
Common Cron Patterns
Every Hour
0 * * * *
Runs at minute 0 of every hour (1:00, 2:00, 3:00...).
Daily at Midnight
0 0 * * *
Every Monday at 9 AM
0 9 * * 1
First of Every Month at Midnight
0 0 1 * *
Every Weekday at 8:30 AM
30 8 * * 1-5
Every 15 Minutes
*/15 * * * *
Twice Daily (9 AM and 6 PM)
0 9,18 * * *
Every Sunday at 3 AM
0 3 * * 0
Last Day of Month
Cron doesn't support "last day" directly. Workarounds:
# Run on days 28-31, but check if it's the last day
0 0 28-31 * * [ "$(date +\%d -d tomorrow)" = "01" ] && /script.sh
Cron vs Cron-like (6 vs 5 Fields)
Some systems (like Quartz, Spring) use 6 fields, adding seconds:
┌───────────── second (0 - 59)
│ ┌───────────── minute (0 - 59)
│ │ ┌───────────── hour (0 - 23)
│ │ │ ┌───────────── day of month (1 - 31)
│ │ │ │ ┌───────────── month (1 - 12)
│ │ │ │ │ ┌───────────── day of week (0 - 6)
│ │ │ │ │ │
* * * * * * command
Spring and Quartz may also support:
?for "no specific value" in day fieldsLfor "last" (last day of month, last Friday)Wfor weekday nearest to given date#for "nth weekday" (e.g.,2#1= first Monday)
Always check which cron flavor your system uses!
Timezone Considerations
Cron times are in the system's local timezone by default.
Problems This Causes
- DST transitions: Jobs may run twice or skip during daylight saving changes
- Server relocation: Moving servers to different timezones affects schedules
- Distributed systems: Servers in different timezones run at different actual times
Solutions
Use UTC where possible:
CRON_TZ=UTC 0 0 * * * /script.sh # Runs at midnight UTCDocument the timezone clearly in comments
Avoid scheduling during DST transitions (2-3 AM)
Testing Cron Expressions
Before deploying, verify your expression:
Manual Verification
Walk through the expression field by field:
30 4 1 * *
│ │ │ │ └─ Any day of week
│ │ │ └─── Any month
│ │ └───── 1st day of month
│ └─────── 4:00 (hour)
└────────── 30 minutes
= "At 4:30 AM on the 1st of every month"
Use Testing Tools
Online cron expression testers show:
- Human-readable explanation
- Next N scheduled runs
- Validation errors
Common Mistakes
1. Forgetting Day of Week is 0-6
0 0 * * 7 # WRONG - some systems don't accept 7
0 0 * * 0 # RIGHT - Sunday is 0
2. Day of Month AND Day of Week
Most crons run if EITHER matches:
0 0 15 * 5 # Runs on the 15th AND every Friday
This probably isn't what you intended!
3. Running Too Frequently
* * * * * # Every minute - probably too often!
Consider: Do you really need this frequency? What about overlap if the job takes >1 minute?
4. No Error Handling
Cron jobs can fail silently. Always:
- Log output and errors
- Set up monitoring
- Handle failures gracefully
0 * * * * /script.sh >> /var/log/script.log 2>&1
5. Missing PATH
Cron uses a minimal environment:
# Set PATH explicitly
PATH=/usr/local/bin:/usr/bin:/bin
0 * * * * my-command
Or use full paths:
0 * * * * /usr/local/bin/my-command
Advanced Tips
Multiple Schedules
Run at multiple times with separate lines:
0 9 * * * /script.sh # 9 AM
0 17 * * * /script.sh # 5 PM
Predefined Schedules
Many systems support shortcuts:
| Shortcut | Equivalent |
|---|---|
@yearly |
0 0 1 1 * |
@monthly |
0 0 1 * * |
@weekly |
0 0 * * 0 |
@daily |
0 0 * * * |
@hourly |
0 * * * * |
@reboot |
Run once at startup |
Lock to Prevent Overlap
Use flock to prevent concurrent runs:
* * * * * /usr/bin/flock -n /tmp/script.lock /path/to/script.sh
Summary
Cron expressions are powerful once you understand them:
- 5 fields: minute, hour, day, month, weekday
- Special characters:
*(any),/(step),-(range),,(list) - Watch for gotchas: timezones, DST, day-of-month vs day-of-week
- Test before deploying: Use tools to verify your expression
- Monitor your jobs: Log output and handle failures
Ready to test a cron expression? Try our Cron Expression Tool!