Cron's time-based scheduling works beautifully for divisors of 60 (like 20 minutes), but becomes tricky when you need intervals that don't perfectly divide hours. The standard cron syntax doesn't directly support 90-minute intervals since 90 isn't a factor of 1440 (minutes in a day).
The approach you've started with is correct in principle - using two alternating schedules that together create the 90-minute pattern. However, your current implementation has two issues:
# Problematic implementation:
0 0,3,6,9 * * * whatever
30 1,4,7,10 * * * whatever
Here's the working version that properly alternates every 90 minutes:
# Run at :00 and :30 past alternating hours
0 */3 * * * whatever
30 1-23/3 * * * whatever
The first line runs at minute 0 of every 3rd hour (0, 3, 6...). The second line runs at minute 30 of every 3rd hour starting from 1 AM (1, 4, 7...). Together they create executions at:
- 12:00 AM
- 1:30 AM
- 3:00 AM
- 4:30 AM
- ...
For more complex scheduling, consider a wrapper script that manages the timing:
#!/bin/bash
# Calculate minutes since midnight
MINUTES=$((10#$(date +"%H") * 60 + 10#$(date +"%M")))
# Check if current time is a multiple of 90
if [ $((MINUTES % 90)) -eq 0 ]; then
# Execute your actual command
whatever
fi
Then set up a cron job to run this script every hour (or even every minute if immediate execution is critical):
* * * * * /path/to/wrapper_script.sh
To test your cron schedule before deployment:
- Use
crontab -l
to verify the job is saved - Check system logs with
grep CRON /var/log/syslog
- Add logging to your script to confirm execution times
Cron is great for running tasks at regular intervals, but it has limitations when dealing with non-divisible time periods. The standard */N syntax works perfectly for intervals that divide evenly into 60 minutes (e.g., 5, 10, 15, 20, 30 minutes). However, when you need something like every 90 minutes, you'll need a different approach.
The attempted solution in the question almost works but misses some critical points:
0 0,3,6,9 * * * whatever
30 1,4,7,10 * * * whatever
This setup would run at:
- 12:00 AM, 3:00 AM, 6:00 AM, 9:00 AM
- 1:30 AM, 4:30 AM, 7:30 AM, 10:30 AM
The gap between runs alternates between 90 minutes (correct) and 150 minutes (incorrect).
Here's the correct way to implement a 90-minute schedule:
0 */3 * * * whatever
30 1-23/3 * * * whatever
This creates a consistent 90-minute pattern throughout the day:
00:00 (midnight)
01:30
03:00
04:30
06:00
07:30
09:00
10:30
12:00 (noon)
13:30
15:00
16:30
18:00
19:30
21:00
22:30
For more complex scheduling needs, consider these alternatives:
1. Using a Wrapper Script:
#!/bin/bash
# Run every 90 minutes
if [ $(( $(date +%s) / 60 % 90 )) -eq 0 ]; then
/path/to/your/command
fi
Then set your cron to run this script every minute:
* * * * * /path/to/wrapper_script.sh
2. Systemd Timers (Linux systems):strong>
[Unit]
Description=Run every 90 minutes
[Timer]
OnCalendar=*-*-* *:0/90:0
Persistent=true
[Install]
WantedBy=timers.target
Always verify your cron jobs:
# Check cron logs
grep CRON /var/log/syslog
# Manually test with:
sudo run-parts --test /etc/cron.d
# For specific user:
crontab -l
- Always include full paths to commands in cron jobs
- Redirect output to log files for debugging
- Consider using flock to prevent overlapping runs
- Test with future times using a tool like 'cronjobchecker.com'