Cron expression for every weekday
The cron expression 0 0 * * 1-5
runs at 12:00 AM, Monday through Friday. The restricted fields are minute 0, hour 0, and day of week 1-5; the remaining asterisks match anything. That works out to 5 runs per week.
0 0 * * 1-5 Field breakdown
| Field | Value | Meaning |
|---|---|---|
| Minute | 0 | The top of the hour (:00) |
| Hour | 0 | 00:00 (midnight) |
| Day of month | * | Every day of the month (1–31) |
| Month | * | Every month (1–12) |
| Day of week | 1-5 | Monday through Friday |
Next runs
- —
- —
- —
- —
- —
Run times are calculated in your browser timezone. The scheduler that executes the job uses its own — always UTC on Vercel Cron, UTC by default on GitHub Actions, the host clock on crontab.
How this schedule works
Cron evaluates the five fields of 0 0 * * 1-5 — minute, hour, day of month, month, day of week — against the clock once a minute and starts the job on any minute where all five match, which cronstrue reads as "At 12:00 AM, Monday through Friday": 5 runs per week. The day-of-week field is numbered 0 to 6 with Sunday at 0, so 1-5 selects Monday, Tuesday, Wednesday, Thursday, and Friday. Day of month is left as an asterisk, so the calendar date is unrestricted and only the weekday decides.
When to use every weekday
Restricting a daily job to Monday through Friday is worth doing whenever the weekend runs would be pure cost: reports nobody reads until Monday, reminders that should not fire on a Saturday, batch work whose input only arrives on business days. The saving is real, since two fifths of the invocations disappear, but the schedule is calendar-blind. It will still fire on a public holiday in the middle of the week, so if holidays matter the job itself has to check the date and exit early.
Common mistakes with every weekday
Weekday schedules go wrong on the calendar, not in the parser. The range 1-5 is Monday to Friday and nothing more: it knows nothing about public holidays, company shutdowns, or the markets where the business week runs Sunday to Thursday. If any of that matters, the job has to check the date itself. The other trap is the both-day-fields rule. Adding a day-of-month value to a weekday schedule makes cron fire when either field matches, so 0 0 1 * 1-5 runs on every weekday and on the 1st — including when the 1st is a Sunday.
Platform snippets
The same expression, ready to paste into the four schedulers that read five-field cron. The notes below each snippet are the ones that follow from this schedule; the cron expression generator lists every caveat for every platform.
GitHub Actions
name: Scheduled workflow
on:
schedule:
- cron: '0 0 * * 1-5'
workflow_dispatch:
jobs:
scheduled:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Run job
run: echo "Running scheduled job" - • Workflows scheduled at the top of the hour may be delayed during high-load periods. Consider offsetting the minute field (e.g. "5 0 * * 1-5") for more reliable timing.
Kubernetes CronJob
apiVersion: batch/v1
kind: CronJob
metadata:
name: my-cron-job
spec:
schedule: "0 0 * * 1-5"
jobTemplate:
spec:
template:
spec:
containers:
- name: job
image: my-image:latest
command: ["/bin/sh", "-c", "echo Running"]
restartPolicy: OnFailure - • Do NOT use CRON_TZ or TZ inside the schedule string. Kubernetes 1.29+ rejects this at creation with a validation error; earlier versions issue a warning. Existing CronJobs using TZ/CRON_TZ will continue to warn on update. Use the timeZone field instead.
Vercel Cron
{
"$schema": "https://openapi.vercel.sh/vercel.json",
"crons": [
{
"path": "/api/cron",
"schedule": "0 0 * * 1-5"
}
]
} - • Hobby plan: invocations occur within the specified hour (e.g. "0 8 * * *" runs between 08:00:00 and 08:59:59).
crontab
# Edit your crontab: crontab -e
0 0 * * 1-5 /path/to/command
# With logging:
0 0 * * 1-5 /path/to/command >> /var/log/cron.log 2>&1 Variations
-
0 9 * * 1-5At 09:00 AM, Monday through Friday Weekdays at 09:00 rather than midnight, which is when a business-day job usually wants to land: at the start of the day it reports on. -
0 0 * * MON-FRIAt 12:00 AM, Monday through Friday The same range with the days named. A range of names reads correctly to anyone, whatever they assume about cron's numbering. -
*/30 * * * 1-5Every 30 minutes, Monday through Friday The weekday restriction applied to a half-hourly job instead of a daily one — the day-of-week field constrains any cadence, not just daily ones. -
0 0 * * 6,0At 12:00 AM, only on Sunday and Saturday The exact inverse: Saturday and Sunday only. Between them the two schedules cover every day of the week with no overlap.
Frequently asked questions
How do I read the cron expression 0 0 * * 1-5?
Read the five space-separated fields left to right as minute, hour, day of month, month, and day of week. In 0 0 * * 1-5 the minute is 0, hour is 0, day of month is *, month is *, day of week is 1-5. Of the operators cron defines, this expression uses only the ones that matter here: an asterisk matches every value in its field and a hyphen defines an inclusive range. Put together, cronstrue reads the whole thing as "At 12:00 AM, Monday through Friday", and a scheduler that checks all five fields once a minute will start the job 5 runs per week.
What timezone does 0 0 * * 1-5 run in?
The expression carries no timezone of its own: it names hour 0, and the scheduler decides which hour 0 that is. Read as UTC, the run lands at 00:00 — 19:00 the previous day in New York, 00:00 in London, and 09:00 in Tokyo on a January date, with daylight saving moving the first two later in the year, so the same UTC instant is 20:00 the previous day in New York in July. That offset crosses a calendar day, and this schedule is pinned to a weekday, so the local weekday moves with it: the Monday, Tuesday, Wednesday, Thursday, and Friday run at 00:00 UTC happens at 19:00 on Sunday, Monday, Tuesday, Wednesday, and Thursday in New York. A job that reads the weekday back from the local clock there will disagree with the expression that scheduled it. Set the zone rather than converting by hand where you can: GitHub Actions defaults to UTC but takes an optional timezone key beside cron, and a Kubernetes CronJob has spec.timeZone, stable since 1.27. Where you cannot, convert deliberately: Vercel Cron is UTC-only, and a Linux crontab follows the host clock unless CRON_TZ overrides it.
Does a weekday cron schedule skip public holidays?
Cron has no concept of holidays. The day-of-week range 1-5 matches Monday through Friday on the calendar and nothing else, so a weekday schedule still fires on New Year's Day if it falls midweek. Holiday awareness has to live in the job: check the date against a holiday calendar at the top of the script and exit early, or gate the work behind a feature flag your team controls. Business-day arithmetic also varies by country, so the check belongs in application code where the relevant locale is known — not in the cron expression.
Related cron schedules
-
0 0 * * 1Every Monday -
0 0 * * 5Every Friday -
0 0 * * 6,0Every weekend -
0 0 * * 0Every week -
0 0 1 * *Every month -
0 0 1 */3 *Every quarter
Build a custom schedule in the cron expression generator, or browse every epochkit tool.