How to run a cron job on weekdays at 9 AM: the 0 9 * * 1-5 schedule

By TechCompare · Updated · How we check

0 9 * * 1-5 is the right schedule for weekdays at 9 AM, but cron reads that 9 from the server's clock, so check the zone before you trust it.

Calculator

Next runs of 0 9 * * 1-5

Example from Mon, Nov 9, 2026 at 8:00 AM.

  1. Mon, Nov 9, 2026 at 9:00 AM
  2. Tue, Nov 10, 2026 at 9:00 AM
  3. Wed, Nov 11, 2026 at 9:00 AM
  4. Thu, Nov 12, 2026 at 9:00 AM
  5. Fri, Nov 13, 2026 at 9:00 AM

0 9 * * 1-5 runs a job at 9:00 AM on Monday through Friday and skips Saturday and Sunday. The first two fields set the time, the two stars leave the day of the month and the month open, and 1-5 picks the weekdays. The line is short, but it can still go wrong in three ways.

Schedule pattern
Weekdays at 9 AM
weekdays-9am
Category
Common Patterns
Standard cron expression patterns

How this is calculated

The five fields are minute, hour, day of the month, month, and day of the week, read left to right. The first 0 pins the job to :00, and the 9 is hour 9 on a 24-hour clock, so the job runs at 9 AM and not 9 PM. The two stars leave the day of the month and the month open, so the job can run in any month. The last field, 1-5, is the day of the week. POSIX defines that field as 0 to 6 with 0 as Sunday, so 1 is Monday and 5 is Friday (POSIX crontab). Put the line in your crontab like this:

crontab
0 9 * * 1-5 /path/to/standup-reminder.sh

That line runs on five days a week. The every-day version, 0 9 * * *, also fires at 9 AM but on all seven, so the weekday range removes Saturday and Sunday and changes nothing else. Compared with a weekly job, 0 9 * * 1, the weekday line runs five times a week instead of once. That's the trade: more runs, each one still at 9 AM.

The first gotcha is about whose 9 AM counts. Cron reads the server's time zone by default. crontab(5) describes a CRON_TZ setting for the cron table, and where your cron supports it, you can set it above the job line to your zone name. Without it, convert the hour yourself. At an offset of -5 hours from UTC, your 9 AM is hour 14 on a UTC server, and at -4 hours it's hour 13. A zone that observes daylight saving changes its offset during the year, so a fixed UTC hour is an hour off for part of it. The time zone page covers the daylight saving details.

The second gotcha is holidays. Cron has no calendar, and its five fields can't name a public holiday or a company closure. The fix belongs in the job, not the schedule. Put a short check at the top of the script that compares today's date with a list of holiday dates and exits early when today is on the list. Keep the list in its own file so you can update it each year without touching the script. The cron line keeps firing every weekday, and the script decides whether there's any work to do.

The third gotcha shows up when someone adds a date to a weekday job. 0 9 1 * 1-5 doesn't mean "weekdays that fall on the 1st." When the day of the month and the day of the week are both restricted, cron runs the job on any day that matches either one. crontab(5) puts it this way: "the command will be run when either field matches the current time." So this line runs on the 1st of every month and on every weekday. For a first Monday or the last day of the month, use the shell tests on the first Monday page and the last day page instead.

A weekday 9 AM job fits a morning report, a standup reminder, or a data pull that should be ready before people start work. Keep in mind that cron doesn't make up missed runs. If the server is down at 9 AM on a Tuesday, that run is simply lost.

Verdict

Run date on the server before you deploy, read the hour it shows, and decide whether 9 means your 9. Keep the day of the month field as *, and handle holidays inside the script, because the five fields can't express either one.

More Cron scenarios

Every 5 minutes
Running a cron job every 5 minutes uses the step operator in the minute field: */5 * * * *.
View details
Every hour
To run a job at the top of every hour, use 0 * * * *.
View details
Daily at midnight
0 0 * * * runs a job at exactly midnight (00:00) every day.
View details

Frequently asked questions

How do I run a cron job Monday to Friday at 9 AM?
Use 0 9 * * 1-5 /path/to/job. The first field is the minute, the second is the hour (9 on a 24-hour clock), the two stars leave the day of the month and month open, and 1-5 limits the runs to Monday through Friday. Then check the server's time zone, because cron reads the 9 from that clock.
Does `1-5` mean Monday to Friday?
Yes, on any cron that follows POSIX. The day of the week runs from 0 to 6 with 0 as Sunday, so 1 is Monday and 5 is Friday (POSIX crontab). Saturday and Sunday never match, so the job skips the weekend.
How do I skip holidays?
Cron can't, because its fields have no calendar. Add a check at the top of the script that compares today's date with a list of holiday dates and exits early when today is on the list. Keep the list in its own file so you can update it each year without touching the script.
Why did my weekday job also run on the 1st of the month?
Because the day of the month field isn't *. When both the day of the month and the day of the week are restricted, cron runs on any day that matches either one, so 0 9 1 * 1-5 runs on the 1st and on every weekday (crontab(5)). Put * in the day of the month field to get weekdays only.
How do I run it at 9 AM in my time zone when the server is on UTC?
Set CRON_TZ to your zone name above the job line in the crontab, where your cron supports it. If yours doesn't support it, convert the hour by hand. At an offset of -5 hours from UTC, your 9 AM is hour 14 UTC, and at -4 hours it's hour 13. In a zone that uses daylight saving, that number changes when the clocks do.