---
title: Every 15 minutes on weekdays? Write the crontab line with the Crontab Generator
description: You need a job every 15 minutes during office hours, Monday to Friday. The crontab line is */15 9-17 * * 1-5, but that runs until 17:45, not 17:00, and at 09:00 in the server's timezone, which may not be yours. Here's how to write a crontab schedule with the free Crontab Generator, check every run before you paste it into crontab -e, and turn it into a complete, logged line.
canonical: https://watchfor.io/blog/how-to-write-a-crontab-schedule
---

# Every 15 minutes on weekdays? Write the crontab line with the Crontab Generator

2026-10-04 · WatchFor Team · Guides · guides, devops, automation

You need a job every 15 minutes during office hours, Monday to Friday. The crontab line is */15 9-17 * * 1-5, but that runs until 17:45, not 17:00, and at 09:00 in the server's timezone, which may not be yours. Here's how to write a crontab schedule with the free Crontab Generator, check every run before you paste it into crontab -e, and turn it into a complete, logged line.

To write a crontab schedule, put five fields before the command: minute,
hour, day of month, month, day of week. "Every 15 minutes from 9 to 5 on
weekdays" is `*/15 9-17 * * 1-5`. Read it back before saving: `9-17` in
the hour field includes the whole 17:00 hour, so the last run is at 17:45,
and the hours are the server's, not yours.

The free [Crontab Generator](/crontab-generator) spells out any expression
in English, shows each field with its allowed range and lists the next five
run times in your timezone, so you can check a line before it goes into
`crontab -e`.

## What this tool answers

*Which five fields give me the schedule I have in mind?* Reach for it when
you're writing a new crontab entry, a Kubernetes CronJob `schedule:` or a
CI cron trigger, and want to see the actual times instead of trusting the
field order from memory. Start from a preset chip (every 5 minutes, hourly,
weekdays at 9:00, 1st of the month) and edit from there.

## A real example

### Writing a crontab schedule for every 15 minutes during office hours

The task: sync orders from a supplier's API every 15 minutes during office
hours on weekdays, and leave their API alone at night and at weekends. We
typed the obvious candidate into the [Crontab Generator](/crontab-generator)
in a browser set to UTC, the timezone of the server it would run on:

![The Crontab Generator with */15 9-17 * * 1-5 entered: the description reads "At minutes */15 of hours 9-17, on weekdays", the field cards show */15, 9-17, *, * and 1-5, and the next 5 runs in UTC are Monday 5 October 2026 at 09:00, 09:15, 09:30, 09:45 and 10:00](/blog/how-to-write-a-crontab-schedule-result.webp)

It reads **"At minutes */15 of hours 9-17, on weekdays"**, and since we
looked on a Saturday the first run is **Monday 5 October at 09:00**, then
every quarter hour. Weekends are skipped, as intended.

Two things the first five runs don't show, and that the field cards
explain:

- **The last run is 17:45.** The hour field `9-17` matches 17, and the
  minute field `*/15` matches 0, 15, 30 and 45 in every matching hour. That's
  9 hours × 4 = **36 runs a day**, the last one 45 minutes after the
  office closes. To stop at 17:00, split it into two lines:
  `*/15 9-16 * * 1-5` and `0 17 * * 1-5` (33 runs).
- **09:00 is 09:00 UTC.** The supplier is in New York, where 09:00 EDT is
  13:00 UTC until US daylight saving ends on 1 November 2026, and 14:00 UTC
  after that. A UTC server needs hours `13-21` now and `14-22` from
  November, or a cron that supports `CRON_TZ`.

**The answer:** for "every 15 minutes, 09:00–17:00 New York time, weekdays"
on a UTC server running cronie, the complete lines are:

```text
CRON_TZ=America/New_York
*/15 9-16 * * 1-5  /usr/local/bin/sync-orders >> /var/log/sync-orders.log 2>&1
0 17 * * 1-5       /usr/local/bin/sync-orders >> /var/log/sync-orders.log 2>&1
```

On Debian or Ubuntu cron, which ignores `CRON_TZ` and uses the system
timezone for scheduling, write the UTC hours and change them when daylight
saving changes, or run the job from a systemd timer, whose `OnCalendar=`
accepts a timezone.

## How to read the results

| What you see | What it means |
| --- | --- |
| **Cron expression** | The five schedule fields only. A whole crontab line with its command fails with "Expected 5 fields", so paste the schedule part. |
| **Preset chips** | Common starting points; click one, then edit. |
| **Description banner** | Your schedule in English. Unusual combinations get a literal reading like "At minutes */15 of hours 9-17". |
| **Field cards** | What you typed per field and the range it accepts. Day of week takes 0–7 or SUN–SAT; 0 and 7 are both Sunday. |
| **Next 5 runs · zone** | Upcoming run times in your browser's timezone, with "in 35 h". |
| **Copy** | Copies the expression, ready for `crontab -e`. |
| **Red box** | A field is out of range, a range is reversed (`17-9`), or there aren't exactly five fields. |

## More ways to use it

- **A nightly job away from the crowd.** `0 0 * * *` is when everyone's
  backups start. Try `23 3 * * *` and confirm it reads "At 03:23".
- **Twice a month.** `0 6 1,15 * *` is the 1st and 15th at 06:00; cron has
  no "every two weeks".
- **Quarterly reports.** `0 7 1 1,4,7,10 *` runs on the first day of each
  quarter; the month field accepts names too (`JAN,APR,JUL,OCT`).
- **Converting a CI schedule.** GitHub Actions `on: schedule` uses the same
  five fields in UTC; paste it and set your machine to UTC to read it as the
  runner will.

## Tips and gotchas

- **End every line with a newline, the last one too.** The format
  (`man 5 crontab`) is five fields, a command and a newline, so a file
  generated by a script without a trailing newline can lose its last entry.
  Editors opened by `crontab -e` normally add it.
- **Escape `%`.** In the command part, an unescaped `%` becomes a newline.
  `$(date +\%F)` works; `$(date +%F)` breaks the line.
- **Use absolute paths.** Cron's `PATH` is minimal and your shell profile
  isn't read. `/usr/local/bin/sync-orders`, not `sync-orders`.
- **Send output somewhere.** Without a redirect, output is mailed to the
  user if a mail system exists, otherwise dropped. `>> file 2>&1` keeps
  both standard output and errors.
- **Stop overlapping runs.** If a run can take longer than 15 minutes, wrap
  it in `flock -n /tmp/sync-orders.lock`, so a slow run doesn't start a
  second copy.
- **User crontab vs `/etc/cron.d`.** Files in `/etc/cron.d` and
  `/etc/crontab` have a sixth field, the user to run as, between the
  schedule and the command. A user crontab (`crontab -e`) does not.

## Check it from the command line too

`crontab -l` shows what's installed; `crontab -e` edits it. To preview the
times, `systemd-analyze` evaluates the equivalent systemd calendar spec:

```bash
TZ=UTC systemd-analyze calendar --iterations=40 'Mon..Fri *-*-* 09..17:00/15:00'
```

```text
    Next elapse: Mon 2026-10-05 09:00:00 UTC
  Iteration #34: Mon 2026-10-05 17:15:00 UTC
  Iteration #35: Mon 2026-10-05 17:30:00 UTC
  Iteration #36: Mon 2026-10-05 17:45:00 UTC
  Iteration #37: Tue 2026-10-06 09:00:00 UTC
```

(trimmed). Iteration 36 is 17:45 on Monday, and 37 jumps to Tuesday 09:00:
the same 36 runs a day the generator implies. To check the hour offset for
another timezone:

```bash
date -u -d 'TZ="America/New_York" 2026-10-05 09:00'
date -u -d 'TZ="America/New_York" 2026-11-02 09:00'
```

```text
Mon Oct  5 01:00:00 PM UTC 2026
Mon Nov  2 02:00:00 PM UTC 2026
```

If a schedule surprises you after it's live, the
[Cron Expression Tester guide](/blog/how-to-test-a-cron-expression) walks
through debugging one, including the day-of-month OR day-of-week rule.

## Keep watching it

Cron doesn't tell anyone when a job stops running. A
[heartbeat monitor](/heartbeat-monitoring) in **Cron job** mode takes the
same expression and an IANA timezone (`America/New_York`), expects a ping
at each scheduled time plus a grace period, and opens an incident when one
is missing or reports a failure. Append the ping to the job:

```text
*/15 9-16 * * 1-5  /usr/local/bin/sync-orders && curl -fsS --retry 3 https://ingest.watchfor.io/p/<token>
```

The monitor validates the expression on save and rejects `@daily`-style
aliases and `7` for Sunday, so use the five-field form with `0`.
[Heartbeat monitoring for cron jobs](/blog/heartbeat-cron-monitoring)
explains grace periods and exit codes.

## FAQ

**How do I run a cron job every 15 minutes?**
`*/15 * * * *` runs at minutes 0, 15, 30 and 45 of every hour. Limit the
hours and days with the other fields: `*/15 9-17 * * 1-5` for weekdays
between 09:00 and 17:45.

**What is the order of fields in a crontab?**
Minute, hour, day of month, month, day of week, then the command. System
crontabs in `/etc/cron.d` add a user name before the command.

**What timezone does crontab use?**
The cron daemon's timezone, which is the system timezone, often UTC on
servers. cronie supports `CRON_TZ=` per crontab; Debian and Ubuntu cron do
not, so convert your local hours to the server's.

---

Canonical page: https://watchfor.io/blog/how-to-write-a-crontab-schedule · All articles: https://watchfor.io/blog/all.md · Site guide: https://watchfor.io/llms.txt
