Cron Expression Complete Guide: Master Job Scheduling
Table of Contents
What is Cron and Why Use It?
Cron is a time-based job scheduler found in Unix-like operating systems including Linux, macOS, and BSD variants. It allows you to schedule scripts and commands to run automatically at specified intervals—hourly, daily, weekly, or monthly.
For developers and system administrators, cron is essential for automating repetitive tasks: database backups, log rotation, report generation, cache clearing, health checks, and more. Instead of manually running tasks, you define the schedule once and cron handles the rest.
The cron daemon (crond) runs continuously in the background, checking its configuration every minute to determine if any scheduled jobs need execution. This makes it highly reliable for mission-critical automation.
Key Benefits
- Reliability: Runs automatically without manual intervention
- Efficiency: Schedule tasks during off-peak hours
- Flexibility: Supports complex schedules beyond simple intervals
- Standardization: Works consistently across Unix systems
Cron Expression Format
A standard cron expression consists of five fields separated by spaces, followed by the command to execute:
┌───────────── minute (0 - 59)
│ ┌───────────── hour (0 - 23)
│ │ ┌───────────── day of month (1 - 31)
│ │ │ ┌───────────── month (1 - 12)
│ │ │ │ ┌───────────── day of week (0 - 6, Sunday = 0)
│ │ │ │ │
* * * * * command
The Five Fields
| Field | Allowed Values | Special Characters |
|---|---|---|
| Minute | 0-59 | * , - / |
| Hour | 0-23 | * , - / |
| Day of Month | 1-31 | * , - / ? L W |
| Month | 1-12 or JAN-DEC | * , - / |
| Day of Week | 0-6 or SUN-SAT | * , - / ? L # |
Field Values and Special Characters
Asterisk (*) — Every Value
The asterisk matches all possible values for that field:
* * * * * # Every minute
0 * * * * # Every hour (at minute 0)
* 12 * * * # Every minute during hour 12
* * 1 * * # Every minute on day 1
* * * * 0 # Every minute on Sundays
Comma (,) — Specific Values
List multiple values separated by commas:
0,30 * * * * # At minutes 0 and 30 (every half hour)
9,12,18 * * * # At hours 9, 12, and 18
0 9,12,18 * * * # At 9:00, 12:00, and 18:00
* 9-17 * * 1-5 # Every minute, hours 9-17, weekdays
Hyphen (-) — Range of Values
Specify a range of consecutive values:
0 9-17 * * 1-5 # 9 AM to 5 PM, Monday to Friday
0 0 1-15 * * # Midnight on 1st through 15th
30 4 * * 0,6 # 4:30 AM on weekends (Sat & Sun)
Slash (/) — Step Values
Use slash to specify increments:
*/15 * * * * # Every 15 minutes
0 */2 * * * # Every 2 hours
0 */6 * * * # Every 6 hours
0 0 */3 * * # Every 3 days at midnight
*/10 9-17 * * 1-5 # Every 10 min during business hours
Question Mark (?) — No Specific Value
Use ? when you don't care about a field (useful for day-of-month or day-of-week):
0 0 15 * ? # 15th of every month (any day)
0 0 ? * MON # First day of month (if Monday)
L — Last
L means "last" and works in day-of-month and day-of-week:
* * L * * # Last day of every month
0 0 L * * # Midnight on last day of month
0 0 L-1 * * # Midnight day before last day
* * 5L * * # Last Friday of every month
W — Weekday
W moves to the nearest weekday:
0 0 15W * * # 15th of month, or nearest weekday
0 0 1W * * # 1st of month, or nearest weekday
# — Nth Occurrence
Specify the nth occurrence of a day:
* * 3#4 * * # Fourth Wednesday (3rd day, 4th occurrence)
0 0 1#1 * * # First Monday of every month
Common Cron Examples
| Expression | Meaning |
|---|---|
* * * * * | Every minute |
0 * * * * | Every hour |
0 0 * * * | Daily at midnight |
0 0 * * 0 | Weekly on Sunday at midnight |
0 0 1 * * | First day of every month |
0 0 1,15 * * | 1st and 15th of every month |
*/5 * * * * | Every 5 minutes |
0 */2 * * * | Every 2 hours |
0 9-17 * * 1-5 | Every hour, 9 AM to 5 PM, weekdays |
0 6 * * 1-5 | Weekdays at 6:00 AM |
30 4 * * * | Daily at 4:30 AM |
0 0 1,8,15,22 * * | Every week on the 8th, 15th, and 22nd |
0 0 * * 0 | Sunday at midnight |
0 22 * * 1-5 | Weeknights at 10 PM |
0 0 L * * | Last day of month at midnight |
Special Time Strings
Cron supports several shortcut strings that simplify common schedules:
@reboot # Run once at startup
@yearly # Run once a year (0 0 1 1 *)
@annually # Same as @yearly
@monthly # Run once a month (0 0 1 * *)
@weekly # Run once a week (0 0 * * 0)
@daily # Run once a day (0 0 * * *)
@midnight # Same as @daily
@hourly # Run once an hour (0 * * * *)
Using Special Strings
@hourly /usr/local/bin/cleanup.sh
@daily /usr/bin/backup-database.sh
@weekly /usr/bin/log-rotation.sh
@monthly /usr/bin/monthly-report.sh
Timezone Considerations
By default, cron runs in the system timezone defined in /etc/localtime or the TZ environment variable. This can cause confusion in distributed systems.
Setting Timezone in Crontab
# Set timezone for this crontab
CRON_TZ=America/New_York
0 9 * * * /scripts/daily-report.sh # Runs at 9 AM New York time
Common Timezone Gotchas
- Daylight Saving Time: Jobs near DST transitions may run twice or not at all
- Server migrations: Timezone may differ between old and new servers
- Container environments: May inherit host timezone or default to UTC
- Cloud services: Often run in UTC regardless of your local time
Recommendation
Always use UTC for cron jobs in distributed systems. Store execution times in UTC, convert to local time only for display purposes.
Troubleshooting Cron Jobs
Common Issues
1. Command Not Found
Cron runs with a minimal PATH. Use absolute paths:
# Wrong (may fail)
* * * * * python script.py
# Correct (always works)
* * * * * /usr/bin/python /path/to/script.py
2. Environment Variables Missing
Set variables explicitly in your crontab:
# Set environment variables
PATH=/usr/local/bin:/usr/bin:/bin
PYTHONPATH=/home/user/python
DATABASE_URL=postgres://localhost/db
0 * * * * /home/user/scripts/check-health.sh
3. Working Directory Issues
Commands may fail if they expect to run from a specific directory:
# Use cd to set working directory
0 * * * * cd /project && ./deploy.sh
# Or use absolute paths throughout
4. Output/Error Not Visible
Redirect output to files for debugging:
# Redirect stdout and stderr to files
0 * * * * /scripts/job.sh >> /var/log/job.log 2>&1
# Email output (requires mail configured)
[email protected]
0 * * * * /scripts/job.sh
Debugging Commands
# List your crontab
crontab -l
# Edit crontab
crontab -e
# View system crontabs
cat /etc/crontab
ls -la /etc/cron.d/
# Check cron logs
grep CRON /var/log/syslog # Debian/Ubuntu
grep CRON /var/log/cron # CentOS/RHEL
tail -f /var/log/syslog | grep CRON
Advanced Patterns
Seconds in Extended Format
Standard cron doesn't support seconds. For extended support, use 6-field format:
# Quartz Scheduler format (with seconds)
0 30 9 * * ? # 9:30:00 AM every day
0 0/15 * * * ? # Every 15 minutes
# Cronicle and others support
*/10 * * * * # Every 10 seconds (if supported)
Complex Business Schedules
# Every weekday at 6 PM (except holidays - requires external logic)
0 18 * * 1-5
# First Monday of each quarter
0 0 1-7 * 1
# Last Friday of month
0 0 L * 5
# Business hours: 9-5, every 15 min, weekdays
*/15 9-17 * * 1-5
Ranges with Lists
# Every 30 minutes, 8 AM to 6 PM, Monday through Friday
0,30 8-17 * * 1-5
# Simplified
*/30 8-17 * * 1-5
# Multiple specific times
0 6,12,18 * * * # 6 AM, noon, 6 PM daily
Using Cron in Programming
Most programming languages have libraries for parsing and managing cron expressions:
JavaScript (node-cron)
const cron = require('node-cron');
cron.schedule('0 9 * * 1-5', () => {
console.log('Running weekday morning task');
}, {
scheduled: true,
timezone: 'America/New_York'
});
Python (croniter)
from croniter import croniter
from datetime import datetime
cron = croniter('0 9 * * 1-5', datetime.now())
next_run = cron.get_next(datetime)
print(f'Next run: {next_run}')
Go (robfig/cron)
import "github.com/robfig/cron/v3"
c := cron.New()
c.AddFunc("0 9 * * 1-5", func() {
fmt.Println("Weekday morning task")
})
c.Start()
Validate your cron expressions instantly with the JieBang Cron Parser tool.
Try Cron Parser Online →