Cron example
Cron Every Other Day
A step in the day-of-month field: midnight on days 1, 3, 5 and so on through 31. It looks like a two-day interval, and for most of the month it behaves like one — but the day-of-month field resets on the 1st, so the run on the 31st is followed by another one the very next day.
By NaveenKumar T · Updated · 5-field crontab expression
What each field means
| Field | Value | Meaning |
|---|---|---|
| Minute | 0 | Minute 0 |
| Hour | 0 | Hour 0 |
| Day of month | */2 | Every 2 days, starting on day 1 |
| Month | * | Every month |
| Day of week | * | Every day of the week |
Next 5 run times
Computing the next runs in your timezone…
The month boundary breaks the interval
Cron matches each field against the calendar independently; it has no memory of when the job last ran. A step of 2 in the day-of-month field therefore expands to the odd days 1,3,5,7,…,31 of whichever month it is. In a 31-day month, the 31st and the following 1st are consecutive runs. In a 30-day month the last run is the 29th, so the gap to the 1st is two days as intended. February resets the pattern again.
The consequence is that this expression is not really every 48 hours — it is every odd-numbered day, which averages out to roughly every other day but is never exactly that across a month boundary. For log rotation or a cleanup sweep, nobody cares. For anything where the interval is part of the contract, it matters.
Getting a true alternate-day schedule
The standard workaround is to run daily and let the command decide. Schedule 0 0 * * * and start the command with a guard such as testing whether the day count since the epoch is even: expr $(date +%s) / 86400 % 2 gives a 0/1 alternation that survives month and year boundaries. The scheduler fires every day; the job runs every second day.
The alternative is to give the state to something that keeps it: a systemd timer with OnUnitActiveSec=2d, a queue with a delayed re-enqueue, or a job runner that records the last successful run. Any of these expresses a real interval, which cron's calendar matching fundamentally cannot.
Nearby schedules that behave predictably
If the intent was simply less than daily, a weekly schedule is far cleaner: 0 0 * * 0 gives a run every Sunday with no calendar surprises, because the day-of-week field cycles perfectly every seven days regardless of month length.
If it was about halving the load rather than the interval, consider keeping the job daily and making it cheaper. A daily incremental almost always beats an every-other-day full run, and it removes the awkward question of what happens when the run that was skipped was the important one.
Build a variant of this schedule with dropdowns and check the next ten runs before you install it.
Open the cron generatorRelated cron examples
Browse every schedule on the cron expression generator, read the cron expression syntax guide for the rules behind the five fields, or the developer tools guides for the longer explanations.