Cron Expressions for Business Hours Only
Not every job needs to run 24/7. Sync jobs that hit a rate-limited third-party API, notification jobs that shouldn't wake anyone at 2 AM, or reports that are only useful during working hours all benefit from being restricted to weekdays and a specific hour range. Cron handles this cleanly by combining the hour and day-of-week fields.
The two fields that matter: hour and day-of-week
┌─ minute (0 – 59) │ ┌─ hour (0 – 23) ← restrict this for "business hours" │ │ ┌─ day/month (1 – 31) │ │ │ ┌─ month (1 – 12) │ │ │ │ ┌─ day/week (0 – 6, 0 = Sunday) ← restrict this for "weekdays" │ │ │ │ │ 0 9-17 * * 1-5 → every hour from 9 AM to 5 PM, Mon–Fri
Common business-hours patterns
0 9 * * 1-5— once, at 9:00 AM, Monday through Friday0 9-17 * * 1-5— every hour on the hour, 9 AM to 5 PM, weekdays*/30 9-17 * * 1-5— every 30 minutes during business hours, weekdays*/15 9-18 * * 1-5— every 15 minutes, 9 AM to 6:45 PM, weekdays0 9,13,17 * * 1-5— three times a day (9 AM, 1 PM, 5 PM), weekdays only0 9-17 * * 1-6— includes Saturday as a working day (common in Indian retail/SME businesses)0 10-18 * * 1-5— a 10 AM to 6 PM shift instead of 9-to-5
Split shifts and lunch-hour exclusions
You can combine a comma-separated list with ranges to express something like "morning and afternoon shift, skip the lunch hour":
# Every 30 minutes from 9 AM–1 PM and 2 PM–6 PM, weekdays # (skips the 1 PM–2 PM lunch hour entirely) */30 9-12,14-17 * * 1-5 # Reads as: hour field = 9,10,11,12,14,15,16,17
Common mistakes with business-hours expressions
- Off-by-one on the end hour.
9-17in the hour field fires at 9:00 through 17:00 (5 PM) — it does not include anything after 17:00. If you want the job to run through 5:59 PM, you need a minute-level trick or explicit values. - Forgetting cron has no holiday calendar.
1-5covers every Monday–Friday including public holidays. If a job must skip holidays (e.g. Diwali, Republic Day), the script itself needs to check a holiday list and exit early. - Mixing up server timezone with "business hours." "9 AM business hours" almost always means local time for your users, not whatever timezone the server defaults to — see our timezone guide below before deploying.
- Using day-of-week 7 for Sunday. Some cron implementations accept 7 as an alias for Sunday, but it's not universal — stick with 0 for portability.
Skipping holidays inside the script
// business-hours-job.js — cron triggers this every hour, 9-5, Mon-Fri;
// the script itself decides whether to actually skip a holiday
const HOLIDAYS_2026 = ['2026-01-26', '2026-03-14', '2026-08-15', '2026-10-02'];
const today = new Date().toISOString().slice(0, 10);
if (HOLIDAYS_2026.includes(today)) {
console.log(`Skipping run — ${today} is a public holiday`);
process.exit(0);
}
runBusinessHoursJob();Frequently Asked Questions
Use 1-5 in the day-of-week field to mean Monday through Friday, for example 0 9 * * 1-5 runs at 9:00 AM every weekday. Day-of-week numbering is 0-6 where 0 is Sunday and 6 is Saturday.
Combine an hour range with a weekday range, for example 0 9-17 * * 1-5 runs at the top of every hour from 9 AM through 5 PM, Monday to Friday. The range 9-17 is inclusive on both ends.
No. Standard cron has no concept of holidays or calendars, only fixed day-of-week and date patterns. To skip holidays, the job script itself must check a holiday calendar (a list or an API) and exit early if today is a holiday.