Blog · · Updated
Cron Expression for Every Monday (0 9 * * 1) and Weekly Schedules
Use 0 9 * * 1 to run a cron job every Monday at 9:00 AM. Examples for crontab, GitHub Actions, Kubernetes CronJob and Node.js, plus day-of-week numbering.
Cron Expression Generator
Build, understand and validate cron expressions.
To run a cron job every Monday at 9:00 AM, use 0 9 * * 1. The fifth field is day of week, and 1 means Monday. For midnight on Monday, use 0 0 * * 1. You can build either one in the Cron Expression Generator and preview the next run times before you deploy it.
The five fields
A standard cron expression has five fields, separated by spaces, in this order:
- Minute (0-59)
- Hour (0-23)
- Day of month (1-31)
- Month (1-12 or JAN-DEC)
- Day of week (0-7, where 0 and 7 are Sunday, or SUN-SAT)
For a weekly job, the first three fields usually set the time and the last field sets the day. Month and day of month stay as *, which means every value.
# minute hour day-of-month month day-of-week 0 9 * * 1
Common Monday schedules
0 0 * * 1 00:00 every Monday (start of Monday) 0 9 * * 1 09:00 every Monday 30 8 * * MON 08:30 every Monday (named day) 0 9 * * 1,5 09:00 every Monday and Friday 0 9 * * 1-5 09:00 Monday through Friday
The midnight entry is easy to misread. 0 0 * * 1 fires at the start of Monday, so for a job that should summarize last week, the run happens just after Sunday ends.
Every Monday in crontab, GitHub Actions, Kubernetes and Node.js
crontab
# m h dom mon dow command 0 9 * * 1 /usr/local/bin/weekly-report.sh >> /var/log/weekly-report.log 2>&1
Add the line with crontab -e. It runs at 09:00 in the server's time zone every Monday.
GitHub Actions
on:
schedule:
# 09:00 Monday in Seoul (UTC+9) is 00:00 Monday UTC
- cron: '0 0 * * 1'
workflow_dispatch:GitHub Actions evaluates schedule in UTC by default, so convert your local time first, and check whether the conversion crosses midnight. Monday 9:00 AM in New York is 14:00 UTC in winter (EST) but 13:00 UTC in summer (EDT), so a fixed 0 14 * * 1 drifts by an hour twice a year. In zones well ahead of UTC the day can change too: Monday 8:00 AM in Sydney (AEST, UTC+10) is Sunday 22:00 UTC, which is 0 22 * * 0.
Kubernetes CronJob
apiVersion: batch/v1
kind: CronJob
metadata:
name: weekly-report
spec:
schedule: "0 9 * * 1"
timeZone: "America/New_York"
jobTemplate:
spec:
template:
spec:
restartPolicy: OnFailure
containers:
- name: report
image: busybox:1.36
command: ["sh", "-c", "echo building weekly report"]With timeZone set, the job runs at 09:00 New York time all year, and Kubernetes handles the switch between EST and EDT. Without it, the schedule uses the controller's time zone, usually UTC.
Node.js
import cron from 'node-cron';
cron.schedule('0 9 * * 1', () => {
sendWeeklyReport();
}, { timezone: 'Europe/London' });node-cron only fires while your Node.js process is running, so a restart during Monday 09:00 means the run is missed. For reports that must not be skipped, use system cron or a Kubernetes CronJob.
Day-of-week numbering: 0 and 7 are Sunday
Day of week counts from Sunday. Here is the mapping:
- 0: Sunday
- 1: Monday
- 2: Tuesday
- 3: Wednesday
- 4: Thursday
- 5: Friday
- 6: Saturday
- 7: Sunday
Both 0 and 7 mean Sunday. Most cron implementations accept both. If you need the widest compatibility, use 0 for Sunday. The most common mistake is treating 0 as Monday because a week starts there in many calendars. In cron, Monday is always 1.
Named days
You can use three-letter names instead of numbers: SUN, MON, TUE, WED, THU, FRI, SAT. They are case-insensitive, so mon and MON both work in implementations that support names. Names make the expression easier to read, especially for ranges and lists.
0 9 * * MON-FRI 0 9 * * MON,FRI
Names are not supported in every minimal cron implementation, so if you write crontabs for embedded devices or small containers, test them first. Numbers work everywhere.
Day of month and day of week use OR, not AND
This is the rule that surprises most people. When both the day-of-month field and the day-of-week field are restricted (neither is *), a standard cron job runs when either one matches. It does not require both to match.
0 9 1 * 1 /usr/local/bin/job.sh
That line does not mean "Mondays that fall on the 1st." It runs at 09:00 on the 1st of every month and at 09:00 every Monday. If you only wanted the 1st, set the day of week to *. If you only wanted Mondays, set the day of month to *.
Some schedulers do not follow this rule. Quartz, for example, requires you to put ? in one of the two fields, and it uses a different numbering for days of the week. Always check the documentation for the system that runs your job.
Harder Monday schedules
Standard cron cannot express "first Monday of the month" or "every other Monday" directly. You can get close with a small wrapper.
For the first Monday of the month, run the job on days 1 through 7, which always contain exactly one Monday, and check the weekday inside the command. date +%u prints the ISO weekday, where Monday is 1. In a crontab, the percent sign must be escaped as \%.
0 9 1-7 * * [ "$(date +\%u)" = 1 ] && /usr/local/bin/job.sh
For every other Monday, a common approach is to run weekly and have the script check whether the ISO week number is even or odd, using date +%V. Keep the zero-padded value in mind when doing arithmetic in shell, because a value like 08 can be parsed as octal.
If your scheduler supports a calendar or interval feature, such as systemd timers or a cloud scheduler, it may be simpler to use that instead.
Time zones and checking your schedule
Cron usually evaluates times in the system's local time zone, not UTC. A server set to UTC will run your Monday 9:00 job at 09:00 UTC, which may be the middle of the night for your team. Run date on the host to see which zone it uses, and check how your platform handles time zones before you rely on the schedule.
Before you deploy, paste the expression into the Cron Expression Generator to confirm the next several run times. It is the fastest way to catch a wrong day number or an OR surprise.
If you need a daily job instead, see Cron Every Day at Midnight. For shorter intervals, see cron every 5 minutes.
FAQ
What cron expression runs every Monday at midnight?
Use 0 0 * * 1. It fires at 00:00 on Monday. If your scheduler uses 1 as Sunday, as Quartz does, the same job would be written differently, so check the documentation.
Is 0 or 7 Sunday in cron?
Both are Sunday in most cron implementations. Use 0 if you want the widest compatibility. Monday is always 1.
Why did my job run on the 1st of the month when I only wanted Mondays?
You probably set both the day of month and the day of week. Standard cron treats those two fields with OR, so the job runs when either one matches. Set the day-of-month field to * to run only on the days of week you specify.
Can cron run a job on every other Monday?
Not with a single five-field expression. Run the job weekly and have the script check the ISO week number, or use a scheduler that supports intervals.
How do I run a GitHub Actions workflow every Monday?
Add a schedule trigger with - cron: '0 9 * * 1' under on:. That runs at 09:00 UTC, so convert your local time to UTC first and check whether the conversion moves the job to Sunday or Tuesday. Preview the result in the Cron Expression Generator.
Cron Expression Generator
Build, understand and validate cron expressions.