Crontab Syntax for Quarterly Jobs: Running Every 3 Months on 1st Day


2 views

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