Field breakdown
Minute 0, hour 9, day of month *, month *, day of
week 1-5. In cron's numbering Sunday is 0 (or 7) and Monday is 1, so 1-5 is
Monday through Friday. You can also write it with names: 0 9 * * MON-FRI, which most
implementations accept and which is considerably harder to misread.
Weekday numbering, in full
| Number | Name | Day |
|---|---|---|
| 0 | SUN | Sunday |
| 1 | MON | Monday |
| 2 | TUE | Tuesday |
| 3 | WED | Wednesday |
| 4 | THU | Thursday |
| 5 | FRI | Friday |
| 6 | SAT | Saturday |
| 7 | SUN | Sunday again — so ranges like 5-7 work |
Quartz and Spring number the week differently, with 1 for Sunday. Copying 1-5 from a
crontab into a Quartz configuration silently shifts the schedule to Sunday through Thursday.
Leave the day-of-month field as *. If you restrict both day-of-month and day-of-week,
cron combines them with OR rather than AND, and 0 9 1 * 1-5 means "09:00 on the 1st of
the month, plus 09:00 every weekday" — not "the 1st, if it is a weekday".
Time zones matter here
Unlike an interval schedule, a fixed-time weekday job is meaningful only in a particular time zone.
Nine in the morning on a UTC server is 10:00 or 11:00 in central Europe depending on the season, and the
previous evening in the Americas. Either set CRON_TZ at the top of the crontab, use the
timeZone field in Kubernetes, or compute the UTC equivalent and accept the twice-yearly
hour of drift.
Using it
# crontab, with an explicit zone (Vixie cron)
CRON_TZ=Europe/Berlin
0 9 * * 1-5 /usr/local/bin/morning-report.sh
# Kubernetes CronJob
spec:
schedule: "0 9 * * 1-5"
timeZone: "America/New_York"
Variations
| Expression | Runs |
|---|---|
| 0 9 * * 1-5 | 09:00, Monday to Friday. |
| 0 9 * * MON-FRI | Identical, using day names. |
| 0 9,17 * * 1-5 | Start and end of the working day. |
| 30 8 * * 1-5 | 08:30 on weekdays — before the inbox fills up. |
| 0 9 * * 1 | 09:00 on Mondays only — a weekly kick-off. |
| 0 9 * * 6,0 | 09:00 at weekends instead. |
| */30 9-17 * * 1-5 | Every half hour through the working day. |