Cron every 2 weeks: what cron cannot do and what to write
No cron expression fires every two weeks, because there is no field for the week number. The two workable approaches are a semi monthly schedule or a weekly schedule with a parity check in the script.
At a glance
- Expression
- 0 0 * * 1 with a week parity guard
- Fires
- 26 fortnights a year, which no single expression produces. The semi monthly alternative gives 24 runs a year.
- Restricted fields
- Depends on the approach. The parity approach restricts day of week only and does the rest in the script.
- Equivalent macro
- None. There is no fortnightly macro, and @weekly cannot be stepped.
- Why it cannot be expressed
- The five fields describe a position in the month and the week, not a repeating count of weeks.
- Semi monthly alternative
- 0 0 1,15 * * gives 24 runs a year, not 26, and the gaps vary from 13 to 16 days.
In detail
Cron matches a timestamp against five independent field patterns. None of those fields counts weeks since some origin, so there is nothing to test for alternation. Every scheme that appears to give a fortnightly cron expression is really a monthly one in disguise, and the difference shows up as two missing runs a year.
The closest expression only alternative is the first and fifteenth of the month. It fires 24 times a year with gaps between 13 and 16 days, which is fine if the requirement is loosely twice a month and wrong if the requirement is exactly every fourteen days. Say which one it is before choosing, because they diverge by a full fortnight over a year.
For a genuine fourteen day cycle, schedule weekly and let the script decide. Dividing the epoch second count by 604800 gives a week number that increases by exactly one every seven days, and testing whether it is even or odd gives a stable alternation that does not care about month lengths or year boundaries.
The tempting alternative, testing whether the ISO week number is even, works for most of the year and then breaks. Some years contain a week 53, so the parity flips at the year boundary and the job runs two weeks running or skips a fortnight. Epoch arithmetic has no such discontinuity.
Examples
0 9 * * 1 [ $(( $(date +\%s) / 604800 \% 2 )) -eq 0 ] && /opt/app/bin/fortnightly.shRuns every second Monday. The percent signs are escaped because cron treats a bare % specially.
0 9 1,15 * * /opt/app/bin/fortnightly.sh24 runs a year, gaps of 13 to 16 days.
0 9 * * 152 or 53 runs a year. The guard in the script halves it.
Things that catch people out
- ISO week parity is not stable across years that contain a week 53. Use epoch arithmetic instead.
- The first and fifteenth is not a fortnight. It is 24 runs a year against 26, and the gap in February is 13 days.
- A parity guard means half the scheduled runs do nothing. If you monitor that the job ran, monitor the guarded work rather than the crontab entry.
Try it: Cron Expression Parser
Paste any five or six field expression to get a plain English description, a per field breakdown and the next run times in your local time.
Cron Expression Parser
LOCAL · Browser-OnlyParse cron expressions and see the next scheduled run times
Supports 5-field (minute hour day month weekday), 6-field (with seconds), named values (JAN, MON), and @macros (@daily, @hourly, ...)
Use the dropdowns below to build your cron expression visually, or type a custom value in each field.
Human-Readable Description
Every 5 minutes
Field Breakdown
| Field | Allowed | Value | Meaning |
|---|---|---|---|
| Minute | 0-59 | */5 | every 5 minute(s) |
| Hour | 0-23 | * | every hour |
| Day of Month | 1-31 | * | every day of month |
| Month | 1-12 | * | every month |
| Day of Week | 0-7 | * | every day of week |
Related cron expressions
All cron expressions →Cron on the 1st and 15th: 0 0 1,15 * *
0 0 1,15 * * runs on the first and fifteenth of every month, 24 times a year. The gaps run from 13 to 17 days, so it is not a fortnight.
Cron every Monday at 9 AM: 0 9 * * 1
0 9 * * 1 runs at 09:00 every Monday, 52 or 53 times a year. Day 1 is Monday, and the fifth field is the only one that needs to change.
Cron every 15 days: 0 0 */15 * * gives days 1, 16 and 31
0 0 */15 * * matches days 1, 16 and 31, so 31 day months get three runs and the gap from the 31st to the 1st is a single day.
Cron macros: @daily, @weekly, @monthly and the rest
Seven macros expand to ordinary five field expressions, and @reboot has no scheduled time at all. Here is exactly what each one becomes.
Cron every other day: 0 0 */2 * * and the month reset
0 0 */2 * * runs on odd numbered days, 16 times in a 31 day month. The step resets each month, so the 31st and the 1st are consecutive runs.
Cron every 3 days: 0 0 */3 * * and what happens monthly
0 0 */3 * * runs on days 1, 4, 7 and so on, 11 times in a 31 day month. The step restarts monthly, so the real gap varies from one to four days.
Tools for this
- Cron Expression Parser Free online cron expression parser - parse cron expressions and see the next scheduled run times
- Timestamp Converter Free online timestamp converter - convert between Unix timestamps and human-readable dates instantly