Quick answer
The cron expression for every hour during business hours is 0 9-17 * * 1-5. The 0 runs the job on the hour, 9-17 is an inclusive range of hours, and 1-5 limits it to Monday through Friday, so it fires nine times a day from 09:00 to 17:00, 45 times a week. Use 9-16 if the last run should be at 16:00.
- Live next runs
- Any time zone
- Field-by-field breakdown
- Seven platform snippets
- Daylight saving aware
How to use this schedule
- 1Copy
0 9-17 * * 1-5with the Copy expression button. - 2Check Next runs in your time zone to confirm it fires when you expect, including around daylight saving changes.
- 3Pick your platform under Use it on your platform and copy the ready-made crontab line, workflow, manifest or timer.
- 4Need a different time or day? Click Customize to open it in the cron expression generator and change any field.
Why does 9-17 give nine runs, not eight?
Cron ranges are inclusive at both ends, so 9-17 means 9, 10, 11, 12, 13, 14, 15, 16 and 17: nine hours, with a run at 17:00 sharp. Whether that is right depends on what "business hours" means for the job. If the office closes at 17:00 and nothing should happen after closing, end the range at 16.
| Expression | Runs per weekday | Last run |
|---|---|---|
0 9-17 * * 1-5 | 9 | 17:00 |
0 9-16 * * 1-5 | 8 | 16:00 |
30 8-17 * * 1-5 | 10 | 17:30 |
0 8-18/2 * * 1-5 | 6 | 18:00 |
The day-of-week field 1-5 is Monday through Friday, with Sunday as 0 (or 7). In countries with a Sunday-to-Thursday working week, use 0-4 instead.
Whose business hours, and what about holidays?
This is the schedule where the time zone matters most. Cron reads the hours in the server's zone, and servers usually run on UTC. On a UTC server, 0 9-17 * * 1-5 fires from 05:00 to 13:00 in New York during daylight time, which is half a working day early. Fix it at the source: set CRON_TZ if your cron supports it (cronie does), add timezone: next to the cron entry on GitHub Actions, use spec.timeZone on a Kubernetes CronJob, or pick a scheduler with time zone support. Converting the hours to UTC by hand works only until daylight saving time changes the offset. When a team spans several zones, use the zone of the people who act on the job's output.
Cron also knows nothing about public holidays. Rather than editing the crontab every year, let the job exit early when today is in a holiday list:
# at the top of the job script
if grep -qx "$(date +%F)" /etc/company-holidays.txt; then exit 0; fiFor finer granularity in the same window, use */15 9-17 * * 1-5; for a single daily run see every weekday at 9am.
What does each field in 0 9-17 * * 1-5 mean?
| Field | Value | Allowed | Meaning |
|---|---|---|---|
| Minute | 0 | 0–59 | at minute 0 (on the hour) |
| Hour | 9-17 | 0–23 | every hour from 09:00 to 17:00 (9 AM to 5 PM) |
| Day of month | * | 1–31 | every day of the month |
| Month | * | 1–12, JAN–DEC | every month |
| Day of week | 1-5 | 0–7 (0 and 7 are Sunday), SUN–SAT | Monday through Friday |
Read together: On the hour from 09:00 to 17:00, Monday to Friday.
How do I adjust 0 9-17 * * 1-5 to my own schedule?
Small edits to 0 9-17 * * 1-5 cover most real-world needs:
| Expression | What it does |
|---|---|
0 9-16 * * 1-5 | Every hour from 09:00 to 16:00 on weekdays, last run before closing |
*/15 9-17 * * 1-5 | Every 15 minutes from 09:00 to 17:45 on weekdays |
30 8-17 * * 1-5 | Every hour at half past, 08:30 to 17:30, Monday to Friday |
0 9-17 * * 0-4 | Every hour from 09:00 to 17:00, Sunday to Thursday |
0 8-18/2 * * 1-5 | Every 2 hours from 08:00 to 18:00 on weekdays |
Need something else? Click Customize at the top of the page to open this schedule in the cron expression generator and change any field.
Related schedules: Every hour · Every weekday at 9am · Every weekday · Every 15 minutes
Browse all schedules in the cron schedule library.
How do I run 0 9-17 * * 1-5 in crontab, GitHub Actions, Kubernetes and the cloud?
| Platform | Write it as | Time zone |
|---|---|---|
| Linux crontab | 0 9-17 * * 1-5 | Server's time zone; CRON_TZ= in cronie |
| GitHub Actions | - cron: "0 9-17 * * 1-5" | UTC by default; add timezone: (IANA name) |
| Kubernetes CronJob | schedule: "0 9-17 * * 1-5" | Set timeZone: (1.27+) |
| Cloudflare Workers | 0 9-17 * * MON-FRI | UTC only; numbers weekdays from 1 = Sunday, so use names |
| Vercel Cron Jobs | 0 9-17 * * 1-5 | UTC only; more than once a day needs Pro (Hobby: once a day) |
| AWS EventBridge Scheduler | cron(0 9-17 ? * MON-FRI *) | Takes a time zone; legacy scheduled rules are UTC only |
| systemd timer | OnCalendar=Mon..Fri *-*-* 09..17:00:00 | Add a zone after the time, e.g. Europe/London |
In a crontab (crontab -e), the full line looks like this:
0 9-17 * * 1-5 /path/to/job.sh >> /var/log/job.log 2>&1The live panel at the top of the page builds complete, copy-ready files for each platform (workflow, CronJob manifest, wrangler.toml, vercel.json, AWS CLI and systemd units) and can shift the schedule to UTC for platforms that need it.
What can go wrong with 0 9-17 * * 1-5?
- Ranges are inclusive, so
9-17includes a run at 17:00. If nothing should happen after closing time, use9-16. - Cron reads the hours in the server's time zone. On a UTC server this schedule runs from 05:00 to 13:00 in New York during daylight time, so set
CRON_TZ(cronie),timezone:(GitHub Actions) orspec.timeZone(Kubernetes) to the office's zone. - Public holidays are invisible to cron. Exit early from the script when today's date is in a holiday list rather than editing the crontab every year.
- An asterisk in the minute field (
* 9-17 * * 1-5) runs the job every minute of the working day: 540 runs a day instead of 9. - On UTC-only platforms (Cloudflare Workers, Vercel, legacy EventBridge rules), the local time this runs at moves by an hour when daylight saving time starts or ends. Use GitHub's
timezone:, KubernetestimeZone, EventBridge Scheduler or cronie'sCRON_TZto pin it to local time.
Frequently asked questions
Last updated by the Playxoft engineering team.