DevToolsmith

Cron Job Every Other Week

Standard cron can’t express “Every other week” in a single expression. Here is the closest schedule, 0 9 * * 1, plus the workaround that fills the gap and copy-ready examples.

Runs 100% in your browser — nothing is uploaded

Cron schedule

Schedule time zone

UTC

Closest cron expression

0 9 * * 1

At 09:00, only on Monday. On its own, it runs on 52 days a year.

Cron has no week-of-year field, so it can’t skip alternate weeks by itself. The usual approach is a weekly schedule, here Mondays at 09:00, with a check that skips every second week.

Workaround: run a job every other week

Divide the Unix time by the number of seconds in a week (604800) to get a week counter that never resets, then run only on even weeks. Week numbers from date +%V are less reliable: years with 53 ISO weeks break the rhythm.

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

The same idea works on every scheduler below: keep the base schedule and put the check at the start of the job’s command or script.

Field by field

FieldValueMatches
minute 0 0
hour 9 9
day of month * every value
month * every value
day of week 1 MON

Examples

crontab

Run crontab -e and add:

0 9 * * 1 /usr/local/bin/job.sh >> /var/log/job.log 2>&1

For the exact schedule, use the workaround line above instead.

Kubernetes CronJob

apiVersion: batch/v1
kind: CronJob
metadata:
  name: my-job
spec:
  schedule: "0 9 * * 1"
  timeZone: "Etc/UTC"          # Kubernetes 1.27+
  concurrencyPolicy: Forbid    # skip a run if the last one is still going
  jobTemplate:
    spec:
      template:
        spec:
          containers:
            - name: job
              image: ghcr.io/acme/job:1.0
          restartPolicy: OnFailure

GitHub Actions

on:
  schedule:
    - cron: '0 9 * * 1'   # UTC

GitHub evaluates schedules in UTC, and runs can start several minutes late at busy times.

systemd timer

# /etc/systemd/system/job.timer
[Unit]
Description=Run job.service every other week

[Timer]
OnCalendar=Mon *-*-* 09:00:00
Persistent=true

[Install]
WantedBy=timers.target

Enable it with systemctl enable --now job.timer, and check the next runs with systemd-analyze calendar "Mon *-*-* 09:00:00". Persistent=true runs a missed job after downtime, which cron can’t do.

AWS EventBridge

cron(0 9 ? * MON *)

EventBridge cron has six fields (the last is the year), uses ? in either the day-of-month or the day-of-week field, and numbers weekdays from 1 (Sunday) to 7. Rules run in UTC; EventBridge Scheduler also accepts a time zone.

Similar schedules: weekly

Have a different schedule? Paste any expression into the Cron Expression Generator, or browse all cron examples.

Sources

Spotted a mistake? Email hello@devtoolsmith.com and we’ll fix it.

Frequently asked questions

How do I run a cron job every other week?

No single standard cron expression does this exactly. Cron has no week-of-year field, so it can’t skip alternate weeks by itself. The usual approach is a weekly schedule, here Mondays at 09:00, with a check that skips every second week. Divide the Unix time by the number of seconds in a week (604800) to get a week counter that never resets, then run only on even weeks. Week numbers from date +%V are less reliable: years with 53 ISO weeks break the rhythm. 0 9 * * 1 [ $(( $(date +\%s) / 604800 \% 2 )) -eq 0 ] && /usr/local/bin/job.sh