Cron expression for every two weeks
Every other Monday at 09:00, with a date check.
Can’t be written in Cron. The runs below follow the workaround.
Next 10 runs
In Cron, worked out in your browser from the current time.
At a glance
- Runs
- 26 in 2027
- Gap between runs
- Always 14 days
- Expressible in
- None directly; tested workarounds for all six
- Clock changes
- No effect in the zones checked
In each dialect
Every expression here is generated by the tester’s own engine and checked run for run against the others, so “Exact” means the same clock times in the same zone. Each one links to the tester.
Cron fields cannot count weeks. Day of week repeats every seven days and day of month restarts each month, so there is no way to skip alternate weeks.
Workaround
Schedule 0 9 * * 1 (at 09:00, on Mondays) and let a shell test go ahead only when the number of whole weeks since 1 January 1970 is even. In a crontab, % must be written \%, or cron cuts the line there.
0 9 * * 1 [ $(( $(date +\%s) / 604800 \% 2 )) -eq 0 ] && /path/to/commandCron fields cannot count weeks. Day of week repeats every seven days and day of month restarts each month, so there is no way to skip alternate weeks.
Workaround
rate(14 days) repeats every 14 days, counted from when the rule or schedule is created, so create it at the moment you want the first run. A day here is 24 hours, so with a Scheduler time zone the run time moves by an hour across a clock change. For a fixed Monday 09:00, schedule 0 9 ? * MON * and have the target skip alternate weeks with the same check as below.
aws events put-rule --name every-two-weeks --schedule-expression "rate(14 days)"Cron fields cannot count weeks. Day of week repeats every seven days and day of month restarts each month, so there is no way to skip alternate weeks.
Workaround
Quartz cron cannot count weeks, but Quartz has a trigger that can. A CalendarIntervalTrigger repeats every two weeks from its start time, so start it on a Monday at 09:00. preserveHourOfDayAcrossDaylightSavings(true) keeps it at 09:00 local when the clocks change.
TriggerBuilder.newTrigger()
.startAt(firstMondayAt9)
.withSchedule(CalendarIntervalScheduleBuilder.calendarIntervalSchedule()
.withIntervalInWeeks(2)
.preserveHourOfDayAcrossDaylightSavings(true))
.build();Cron fields cannot count weeks. Day of week repeats every seven days and day of month restarts each month, so there is no way to skip alternate weeks.
Workaround
Schedule 0 9 * * 1 and put the test in front of the container’s command, so the Job exits straight away unless the number of whole weeks since 1 January 1970 is even. The test uses GNU date, so Alpine and other BusyBox images need coreutils. The container’s clock is UTC unless you set TZ; match it to timeZone.
schedule: "0 9 * * 1"
# in the container:
command: ["sh", "-c", "[ $(( $(date +%s) / 604800 % 2 )) -eq 0 ] && exec /app/job"]Cron fields cannot count weeks. Day of week repeats every seven days and day of month restarts each month, so there is no way to skip alternate weeks.
Workaround
Schedule 0 9 * * 1 and make the test the first line of the step that does the work, so the step ends early unless the number of whole weeks since 1 January 1970 is even. The runner’s clock is UTC; if you set timezone, give the step the same zone with env: TZ.
- cron: '0 9 * * 1'
# in the job:
- run: |
[ $(( $(date +%s) / 604800 % 2 )) -eq 0 ] || exit 0
./your-scriptCron fields cannot count weeks. Day of week repeats every seven days and day of month restarts each month, so there is no way to skip alternate weeks.
Workaround
Schedule 0 0 9 * * Mon and return early unless the number of whole weeks since 1 January 1970 is even. UtcNow matches the default UTC schedule; if you set WEBSITE_TIME_ZONE, compare local time instead.
[TimerTrigger("0 0 9 * * Mon")]
// first line of the function:
if (DateTimeOffset.UtcNow.ToUnixTimeSeconds() / 604800 % 2 != 0) return;About this schedule
Cron fields have no idea of week parity: day of week repeats every week and day of month restarts every month, so no dialect here can say “every other Monday”. The reliable fix is to run every Monday and let a date check skip alternate weeks. Counting whole weeks since 1 January 1970 keeps the rhythm unbroken across year ends, which ISO week numbers do not, because some years have 53 weeks.
Clock changes
None of these times falls in the hour that clocks skip or repeat in New York, London, Berlin, Helsinki or Sydney, so every dialect runs it normally all year there. Zones that change clocks at other hours can still differ.
Questions
- What is the cron expression for every two weeks?
- None of the six dialects can say it in one expression. Schedule
0 9 * * 1(at 09:00, on Mondays) and let a shell test go ahead only when the number of whole weeks since 1 January 1970 is even. In a crontab,%must be written\%, or cron cuts the line there. - Can I use ISO week numbers for every other week?
- You can, but years with 53 weeks break the pattern: week 53 and week 1 are both odd, so the rhythm slips at that year end. Counting weeks since 1970, as the check on this page does, never slips.