When you need to schedule a task to run every 3 months (quarterly) on the first day of those months, cron's syntax requires careful attention to both month and day-of-month fields. The standard cron format consists of five time fields:
┌───────────── minute (0 - 59) │ ┌───────────── hour (0 - 23) │ │ ┌───────────── day of month (1 - 31) │ │ │ ┌───────────── month (1 - 12) │ │ │ │ ┌───────────── day of week (0 - 6) │ │ │ │ │ * * * * *
For running on the first day of every third month (e.g., January 1, April 1, July 1, October 1), use this crontab entry:
0 0 1 */3 * /path/to/your/script.sh
Alternatively, you could explicitly specify the months:
0 0 1 1,4,7,10 * /path/to/your/script.sh
To test your cron job before deployment, consider these approaches:
# Dry-run with future dates using 'cronviz' or similar tools cronviz "0 0 1 */3 *" # Check next 10 execution times for i in {1..10}; do echo "Run $i:"; date -d "$(date -d "$(crontab -l | grep yourjob | head -1 | awk '{print $1,$2,$3,$4,$5}')" +'%Y-%m-%d %H:%M:%S') + $i months"; done
For complex scheduling needs, consider these alternatives:
1. Systemd timers (more modern approach): [Unit] Description=Quarterly job [Timer] OnCalendar=*-01,04,07,10-01 00:00:00 Persistent=true [Install] WantedBy=timers.target 2. Anacron (for systems that might be offline): @quarterly 45 cron.quarterly /path/to/script
- The */3 syntax in month field might behave differently across cron implementations (Vixie cron vs. others)
- Daylight saving time transitions could affect execution timing
- Permission issues with the script being executed
- Environment variables not being inherited in cron context
Always test your cron jobs in a staging environment before deploying to production. Consider adding logging to verify execution:
0 0 1 */3 * /path/to/script.sh >> /var/log/quarterly.log 2>&1
Cron jobs are scheduled using a specific syntax with five time fields:
* * * * * command_to_execute ┬ ┬ ┬ ┬ ┬ │ │ │ │ │ │ │ │ │ └───── day of week (0 - 6) (0 is Sunday) │ │ │ └────────── month (1 - 12) │ │ └─────────────── day of month (1 - 31) │ └──────────────────── hour (0 - 23) └───────────────────────── min (0 - 59)
To run a job on the first day of every third month (January, April, July, October) at midnight:
0 0 1 1,4,7,10 * /path/to/your/script.sh
Breakdown of this entry:
- First 0: Minute (0 = top of the hour)
- Second 0: Hour (0 = midnight)
- 1: Day of month (first day)
- 1,4,7,10: Months (January, April, July, October)
- *: Every day of the week
For systems using modern cron implementations (like Vixie cron), you can use step values:
0 0 1 */3 * /path/to/your/script.sh
Note that the step syntax (e.g., */3) behaves differently across cron implementations. The explicit month list (1,4,7,10) is more portable.
After adding the entry to your crontab (using crontab -e
), verify it appears in your cron list:
crontab -l
To test if your cron syntax is correct without waiting for actual execution, use:
# For systems with systemd: systemctl list-timers # For checking cron logs: grep CRON /var/log/syslog
Here's a complete example for a quarterly database backup:
0 0 1 1,4,7,10 * /usr/bin/mysqldump -u backup_user -p'password' --all-databases | gzip > /backups/db_$(date +\%Y\%m\%d).sql.gz
Key considerations:
- Use absolute paths for commands
- Escape percent signs in date format strings
- Consider redirecting output to a log file
If your cron job isn't executing:
- Check that the cron service is running:
sudo service cron status
- Ensure the script has execute permissions:
chmod +x /path/to/script.sh
- Verify environment variables - cron runs with a minimal environment
- Check script paths - cron may have a different PATH than your shell