A cron expression that runs once per week:
0 0 * * 0
Field by field: minute 0, hour 0, every day-of-month, every month, day-of-week 0 (Sunday). The job fires at midnight every Sunday. 52 fires per year. The page above generates this and other weekly variants; this companion explains the day-of-week numbering and weekly-cadence considerations.
Day-of-week numbering
The day-of-week field accepts numbers 0–6 (or sometimes 0–7) and, in most implementations, three-letter abbreviations.
| Numeric | Abbreviation | Day |
|---|---|---|
| 0 (or 7) | SUN | Sunday |
| 1 | MON | Monday |
| 2 | TUE | Tuesday |
| 3 | WED | Wednesday |
| 4 | THU | Thursday |
| 5 | FRI | Friday |
| 6 | SAT | Saturday |
Sunday accepts both 0 and 7 in Vixie cron — a deliberate ambiguity to support both ISO 8601 (Monday=1) and US conventions (Sunday=0). Some schedulers only accept one; 0 is the safer portable choice.
Common weekly variants
0 0 * * 0 ← midnight Sunday (most common "weekly" default)
0 0 * * 1 ← midnight Monday — the start of the work week
0 3 * * 0 ← 3 AM Sunday — off-peak
0 17 * * 5 ← 5 PM Friday — end-of-business reports
0 0 * * 1-5 ← midnight on every weekday — five fires per week, not "weekly"
0 0 * * SAT ← Saturday using abbreviation
@weekly ← Vixie cron shorthand for "0 0 * * 0"
Picking the right day
The day to schedule a weekly job depends on what the job does:
- Reports of the previous week. Run Monday morning, when the week’s data is complete and recipients want it before their week starts.
- Off-peak maintenance. Run Sunday early morning — least traffic for most consumer-facing systems.
- Internal cleanup. Saturday or Sunday — out of business hours.
- Pre-week setup. Sunday evening — refresh staged data so Monday morning’s processes have it ready.
- Mid-week health audits. Wednesday — far enough from weekend that anomalies are detectable, far enough from Friday that there’s time to fix issues.
There’s no single right answer. The wrong answer is “midnight Sunday by default for everything,” because all weekly jobs then pile up on the same minute.
Multiple times per week
The day-of-week field accepts lists and ranges. To run multiple days a week:
0 9 * * 1,3,5 ← Monday, Wednesday, Friday at 9 AM
0 0 * * 1-5 ← every weekday at midnight (5 fires/week, not weekly)
0 0 * * 6,0 ← weekends only (Saturday and Sunday)
0 0 * * 0,3 ← Sunday and Wednesday
These aren’t strictly “weekly” — they’re multiple-times-per-week — but they’re the natural extensions of the weekly schedule.
Day-of-week / day-of-month interaction
0 0 1 * 0 is not “midnight on the 1st of the month, but only if the 1st is a Sunday.” Standard cron’s OR rule means it’s “midnight on the 1st OR every Sunday” — about 5–6 fires per month.
If you want “the first Sunday of the month” (or “the second Tuesday,” etc.), standard cron can’t express it. Workarounds:
- Quartz-style
#operator (cloud schedulers, Quartz).0 0 ? * SUN#1is “the first Sunday of the month.” - Bash check inside the script. Run every Sunday with
0 0 * * 0and have the script exit unlessdate +%dis between 1 and 7.
Daylight saving and weekly jobs
Weekly jobs at 3 AM are largely DST-safe in most US/EU timezones — DST transitions happen between 2 AM and 3 AM, so a 3 AM job runs once even on transition Sundays. A 2 AM job on a Sunday DST transition either runs twice (fall) or doesn’t run at all (spring) on that specific Sunday.
Most weekly jobs run on weekends, which is exactly when DST transitions happen, so this trap is more relevant than the daily case. UTC scheduling sidesteps it.
Common pitfalls
- Sunday vs Monday confusion. ISO 8601 says Monday=1 (week starts Monday); cron says Sunday=0 (week starts Sunday). For weekly jobs this matters when the schedule says “every Sunday at the start of the week” and the implementer thinks “Sunday is the end of the week.”
- Treating
1-5as “weekly.” That’s “every weekday” — five times a week. Pick a single day for true weekly cadence. - Day-of-week and day-of-month set to non-
*. OR semantics, fires more often than expected. - Long-running weekly jobs. A weekly aggregation that runs 6 hours is fine — but if it occasionally takes 8 days, the next week’s run starts before the current finishes. Wrap with
flockor have an in-job state check. - Assuming
@weeklyis portable. Most schedulers accept it; some don’t. The five-field form is the safer default.
For other cadences, see cron daily, cron monthly, cron expression generator. For decoding an existing weekly expression, cron parser.