Skip to content
Webmaster Tools
Dev utilitiesCron ParserEvery other day

Cron every other day

The usual cron for every other day is 0 0 */2 * *, but it runs on odd days and restarts each month, so some runs are back to back. How to get an exact 48 hours.

Cron expression
0 0 */2 * *
See the next run times

The expression

0 0 */2 * *

Runs at midnight on the 1st, 3rd, 5th … 29th and 31st of every month: on odd-numbered days, not strictly every 48 hours.

Field Value Meaning
Minute 0 at minute 0
Hour 0 at midnight
Day of month */2 every 2nd day, starting at 1: 1, 3, 5 … 31
Month * every month
Day of week * any day of the week

Why it isn't exact

A step like */2 counts within the field, and the day-of-month field starts again at 1 every month. So the pattern breaks at month ends:

  • After a 31-day month: runs on the 31st and the 1st, two days in a row.
  • After a 30-day month: the 29th, then the 1st, a normal two-day gap.
  • February: the 27th then 1 March in common years; in leap years the 29th and then the 1st, back to back again.

That's seven back-to-back pairs a year. For "roughly every other day" (cleaning temp files, refreshing a cache) it doesn't matter. For anything billed, rotated or rate-limited per 48 hours, it does.

Exactly every 48 hours

Standard cron can't count days across months, so the usual fix is to run daily and let the command skip alternate days, using the day number since the Unix epoch:

0 0 * * * [ $(( $(date +\%s) / 86400 \% 2 )) -eq 0 ] && /usr/local/bin/job.sh

% must be written \% inside a crontab, because cron turns a bare % into a newline. The epoch day count is in UTC; if the server's midnight isn't close to UTC midnight, pick a run time such as noon so daylight saving can never push two runs into the same UTC day.

Other ways to get a true interval:

  • systemd timer: OnUnitActiveSec=2d (with OnBootSec= for the first run) counts 48 hours from the last run. OnCalendar=*-*-1/2 has the same odd-day problem as cron.
  • AWS EventBridge: rate(2 days) is a real two-day interval from when the rule was created.

Variants

Schedule Expression
Even days (2, 4 … 30) 0 0 2-30/2 * *
Every other day at 9am 0 9 */2 * *
Monday, Wednesday, Friday 0 0 * * 1,3,5
Every 3 days (1, 4, 7 … 31) 0 0 */3 * *
Every day 0 0 * * *
Every other week workaround

Monday-Wednesday-Friday is often what "every other day" really means at work, and it's exact every week.

Where to write it

  • crontab: 0 0 */2 * * command, or the daily line with the epoch test above.
  • GitHub Actions: cron: '0 0 */2 * *' in UTC, with the same month-end behaviour. For an exact interval, schedule daily and add a first step that exits when $(( $(date +%s) / 86400 % 2 )) is 1 (no escaping outside crontab).
  • Kubernetes CronJob: schedule: "0 0 */2 * *" with timeZone:; same caveat.
  • AWS EventBridge: cron(0 0 1/2 * ? *) for the odd-day pattern, or rate(2 days) for the exact one.

Paste it into the Cron Expression Parser and look at the runs around the end of a 31-day month.