Tools mentioned in this article
Open the browser-based tool while you read and try the workflow immediately.
A single line like 0 3 * * 1-5 expresses “run at 3:00 AM on weekdays”—that is the power of a Cron expression. From Linux crontab to GitHub Actions, Kubernetes CronJob, and most cloud schedulers, the world of scheduled execution runs on this syntax.

This article breaks down the five fields and special characters of Cron, pairing each expression with what it actually means. At the end you’ll find common pitfalls and an FAQ.
The Basic Structure: Five Fields
A standard crontab expression consists of five fields separated by spaces.
┌───────────── minute (0 - 59)
│ ┌───────────── hour (0 - 23)
│ │ ┌───────────── day of month (1 - 31)
│ │ │ ┌───────────── month (1 - 12)
│ │ │ │ ┌───────────── day of week (0 - 7, 0 and 7 = Sunday)
│ │ │ │ │
* * * * *
The valid range for each field is as follows.
| Field | Range | Notes |
|---|---|---|
| Minute | 0–59 | |
| Hour | 0–23 | 0 = midnight, 23 = 11 PM |
| Day of month | 1–31 | |
| Month | 1–12 | JAN–DEC also valid (depends on implementation) |
| Day of week | 0–7 | 0 and 7 = Sunday, 1 = Monday; SUN–SAT also valid |
Note: GitHub Actions and Kubernetes use this 5-field format. Quartz and AWS EventBridge add “seconds” and/or “year” fields (6–7 fields), which require special characters like
?andLdescribed below.
Understanding Special Characters by Example
Cron’s expressiveness comes from the special characters allowed in each field.
| Symbol | Meaning | Example | Reads as |
|---|---|---|---|
* | every value | * * * * * | every minute |
, | list of values | 0 9,12,18 * * * | daily at 9, 12, and 18 |
- | range | 0 9-17 * * * | daily, on the hour from 9 to 17 |
/ | step interval | */15 * * * * | every 15 minutes |
? | no specific value (day/weekday) | 0 0 ? * MON | every Monday at 0:00 |
L | last | 0 0 L * * | last day of every month at 0:00 |
W | nearest weekday | 0 0 15W * * | the weekday nearest the 15th |
# | nth weekday | 0 9 ? * MON#1 | first Monday at 9:00 |
Note that ?, L, W, and # are extensions of Quartz-style schedulers (Spring, Jenkins, EventBridge) and are not available in standard crontab.
Reading the / (step)
*/15 means “start at 0, step by 15,” i.e. 0,15,30,45. Combined with a range, you can set the starting point.
*/15 * * * * → minutes 0,15,30,45 (every 15 minutes)
5/10 * * * * → minutes 5,15,25,35,45,55 (every 10 min from 5)
0 9-17/2 * * * → hours 9,11,13,15,17 (every 2 hours, 9 to 17)
Common Scheduling Examples
Copy-paste patterns that come up often in practice.
| What you want | Cron expression |
|---|---|
| Every minute | * * * * * |
| Every 5 minutes | */5 * * * * |
| Every hour (on the hour) | 0 * * * * |
| Daily at midnight | 0 0 * * * |
| Daily at 9:30 AM | 30 9 * * * |
| Weekdays at 3 AM | 0 3 * * 1-5 |
| Every 30 min, 9–18 on weekdays | */30 9-18 * * 1-5 |
| Every Monday at 9 AM | 0 9 * * 1 |
| First day of month at 0:00 | 0 0 1 * * |
| Last day of month (Quartz) | 0 0 L * * |
| First Monday at 9 AM (Quartz) | 0 9 ? * MON#1 |
Common Pitfalls
1. Specifying both day-of-month and day-of-week is an OR condition
0 0 1 * 1 means “midnight on the 1st OR on Monday”—not “when the 1st is a Monday.” This is counterintuitive, so specify only one and leave the other as * (or ? in Quartz).
2. Timezone depends on the runtime environment
Many cron daemons use the server’s timezone, while containers and CI commonly run in UTC. 0 0 * * * may fire at UTC midnight rather than your local midnight. If you want 2 AM in JST (UTC+9), the UTC expression is 0 17 * * *.
3. Leaving the minute field as * runs it every minute
* 3 * * * (intending “once at 3 AM”) actually runs 60 times during the 3 AM hour. For “once, at 3:00 sharp,” use 0 3 * * *.
4. Overlapping runs with short intervals
If a job scheduled every 5 minutes takes longer than 5 minutes, the next run starts before the previous finishes, causing overlap. Allow margin in the interval or add a locking mechanism.
Remove the “pre-save anxiety” with a tool
Cron expressions take practice to read and write, and the pitfalls above are hard to spot by eye. The Cron Expression Parser translates your expression into plain language and simulates the next run times, so you can verify the schedule at a glance before deploying.
Frequently Asked Questions
Is Sunday 0 or 7 in a Cron expression?
Most implementations accept both 0 and 7 for Sunday. Monday is 1 and Saturday is 6. To avoid confusion, use the three-letter names (SUN, MON, …) where supported.
How do I express “the last day of the month”?
In environments that support L (Quartz, EventBridge), use 0 0 L * *. Standard crontab has no L, so you need a workaround: run on candidate end-of-month days (28–31) and check the date in your script, or compute it programmatically.
How do I handle the difference between UTC and local time?
Subtract your UTC offset from the hour field. For JST (UTC+9), JST 2 AM becomes UTC 5 PM the previous day, i.e. 0 17 * * *. If your scheduler supports an explicit timezone setting, that is the most reliable option.
Are */5 and 0/5 the same?
In the minute field they are effectively identical (“every 5 minutes”: 0,5,10,…). */5 means “the whole range, stepping by 5,” while 0/5 means “from 0, stepping by 5.” The explicit start form helps when you want to offset the start (e.g. 7/15).