Migrate to RunxBuild and earn up to $50 in hosting credit on your first deposit.

Calculate your savings
unxBuild
Back to Blog Explainer

Cron Definition: The Five Fields, the Six-Field Variant, and the One That Always Trips People Up

Sean

Platform Writer

Jun 20, 2026
7 min read

A cron definition is five fields plus a command, in this order: minute, hour, day-of-month, month, day-of-week. Anything you read or write as a cron expression is one of those five fields with a value, a list, a range, a step, or an asterisk. The six-field variant adds a year at the end and shows up in Quartz, Spring, and a handful of Java job schedulers, not in standard cron.

The one that always trips people up is the day-of-week field. It runs 0-6 in Vixie cron (Sunday is 0 or 7) and 1-7 in Quartz (Sunday is 1, Saturday is 7, both 0 and 7 are invalid). The same cron expression that means “every Sunday at midnight” in Vixie cron is an error in Quartz. This is the most common reason a job that worked on the developer’s laptop fails on the scheduler.

The other two traps: the asterisk in the day-of-month and day-of-week fields, when both are non-*, means “either-or, not and.” A job with 0 0 1 * 1 runs at midnight on the 1st of the month AND on every Monday, not at midnight on the 1st only if it is a Monday. And the daylight saving transition: a job scheduled for 2:30am on a spring-forward day will not run, because 2:30am does not exist that day. Cron does not know about this. The job simply skips.

Cron definition: the five fields, the six-field variant, and the one that always trips people up

Table of contents

The standard 5-field format

Vixie cron, the cron that runs on Linux and macOS, takes a line in crontab like this:

* * * * * command-to-run

Read the fields left to right:

  • Minute — 0 to 59.
  • Hour — 0 to 23 (24-hour clock, not 12-hour with AM/PM).
  • Day of month — 1 to 31.
  • Month — 1 to 12 (or the three-letter abbreviation, JAN-DEC).
  • Day of week — 0 to 7 (Sunday is 0 or 7; Monday is 1, Saturday is 6).

A real example:

30 2 * * 1 /usr/local/bin/backup.sh

This runs backup.sh at 2:30am every Monday. The minute is 30, the hour is 2, the day-of-month is * (every day), the month is * (every month), the day-of-week is 1 (Monday). The shell runs the command when all five fields match the current time.

A list of values, separated by commas, matches any of them:

0 9,17 * * 1-5 /usr/local/bin/report.sh

9am and 5pm, Monday through Friday. The 1-5 is a range (Monday through Friday). The 9,17 is a list (two specific hours).

A step, written as */n, means “every n”:

*/15 * * * * /usr/local/bin/ping.sh

Every 15 minutes. The */15 is “every 15 minutes starting at 0.” The first run is at minute 0, the second at minute 15, and so on.

The combination of these four shapes — value, list, range, step — covers every cron expression you will ever write. The asterisk is the “every” case, the value is the “this one” case, the list is the “these ones” case, the range is the “from this to that” case, and the step is the “every n” case.

The 6-field variant and where it appears

Quartz, Spring’s @Scheduled, and the AWS EventBridge cron expressions all use a six-field variant with the year at the end:

* * * * * *  command
- - - - - - -
| | | | | |
| | | | | +--- year (optional in some, required in others)
| | | | +----- day of week
| | | +------- month
| | +--------- day of month
| +----------- hour
+------------- minute

Quartz uses 1-7 for the day-of-week, with Sunday as 1. AWS EventBridge uses 1-7 with Sunday as 1, same as Quartz. Spring’s @Scheduled follows the same convention when configured with a year.

The trap: the same expression that works on a developer’s Linux laptop with Vixie cron will fail on a Quartz scheduler because the day-of-week is in a different range. The fix is to know which scheduler you are targeting and to use the range that scheduler expects. There is no universal “cron.”

For Kubernetes CronJob, the format is the same as Vixie cron — 5 fields, no year, day-of-week 0-6. For GitHub Actions schedule: cron:, the format is also 5 fields, with a quirk: GitHub uses 0-6 but treats both 0 and 7 as Sunday. So 0 0 * * 0 and 0 0 * * 7 both mean Sunday in GitHub Actions.

The asterisk and what it actually means

The asterisk is shorthand for “every valid value in this field.” In the minute field, * means every minute from 0 to 59. In the hour field, every hour from 0 to 23. In the day-of-month field, every day from 1 to 31. And so on.

The trap: the asterisk in the day-of-month and day-of-week fields at the same time is an error in cron, because cron will never match both. The cron daemon is happy to accept the expression, and the job will run every minute of every day, because at any given minute, at least one of the two fields matches. This is almost never what was intended.

The fix: use a specific value in one of the two fields. 0 0 1 * * is “midnight on the 1st of the month” — the day-of-week is *, the day-of-month is 1. 0 0 * * 1 is “midnight every Monday” — the day-of-month is *, the day-of-week is 1. If both fields need to be specific, the expression is going to be more specific than cron supports and you have to write the matching logic in the script the cron runs.

The day-of-week range trap

The same expression means different things on different schedulers.

SchedulerDay-of-week rangeSunday is
Vixie cron (Linux, macOS)0-6 or 0-70 or 7
Quartz, Spring @Scheduled1-71
AWS EventBridge1-71
Kubernetes CronJob0-60
GitHub Actions schedule0-6 or 0-70 or 7

A cron expression like 0 0 * * 7 (midnight on Sunday) works in Vixie cron and in GitHub Actions, fails in Quartz (because 7 is out of range — Quartz treats 7 as Saturday and Sunday as 1). The same expression written as 0 0 * * 0 works in Vixie cron, Kubernetes, GitHub Actions, and is invalid in Quartz (because 0 is out of range for Quartz).

The right move: always use the name (SUN, MON) instead of the number, if the scheduler supports it. Vixie cron, Quartz, and Spring all accept the three-letter abbreviation. The names are the same on every scheduler.

The wrong move: copy-paste a cron expression from a Stack Overflow answer that worked on a Linux server, paste it into a Quartz config, and wonder why the job never runs.

The “every X minutes” pattern and the @ shorthand

The step syntax, */n, is the way to write “every n units”:

*/5 * * * * /usr/local/bin/job.sh

Every 5 minutes. The */5 is “every 5 minutes starting at 0,” so the runs are at minute 0, 5, 10, 15, … 55 of every hour.

A step does not have to start at 0. 5-55/10 is “minutes 5, 15, 25, 35, 45, 55.” 15-45/10 is “minutes 15, 25, 35, 45.” This is useful when the job should not run at the top of the hour, which is when every other cron job in the world is also trying to run.

Vixie cron also supports shorthand strings:

  • @reboot — run once at startup.
  • @hourly0 * * * *.
  • @daily0 0 * * *.
  • @weekly0 0 * * 0.
  • @monthly0 0 1 * *.
  • @yearly / @annually0 0 1 1 *.

The shorthand is easier to read but covers the common cases only. Anything more specific is a five-field expression.

Daylight saving and why cron hates it

Cron does not know about time zones in any sophisticated way. It runs in the system’s local time, and on the spring-forward day (the day the clock jumps from 2am to 3am), the hour 2 does not exist. A cron expression of 30 2 * * * will not run on that day, because 2:30am does not exist.

The fall-back day is the inverse problem. The clock goes from 2am back to 1am, so the hour 1 happens twice. A cron expression of 30 1 * * * will run twice on that day.

The fixes:

  • Schedule the job in UTC. The system’s TZ environment variable, or a CRON_TZ setting in the crontab, sets the time zone. UTC does not have daylight saving, so the spring-forward and fall-back issues disappear.
  • Schedule the job for a time of day that is unaffected by the transition, like 3:30am (always after the spring-forward, always after the fall-back in regions that observe it).
  • Use a scheduler that understands time zones properly, like systemd timers with Persistent=true, or a job runner that has its own time-zone handling.

For a managed platform that schedules cron jobs for you, the time zone is set in the dashboard and the platform handles the transition. The job still skips the spring-forward hour, but the skip is documented and the team knows about it.

The right way to test a cron expression

Two steps. First, validate the expression with crontab.guru (or the equivalent for the scheduler you are using — Quartz has a similar tool). crontab.guru accepts a five-field expression, tells you what it means in plain English, and shows the next 10 runs based on the current time. The English description is the right place to look for the day-of-week trap.

Second, test the command by running it by hand, in the same environment the cron daemon will run it in. Cron runs commands with a stripped-down environment — no ~/.bashrc, no ~/.zshrc, no shell aliases. A command that works in an interactive terminal may fail in cron because PATH is different, the current working directory is different, or the shell is different. The fix is to set the full path to every binary, set the working directory at the top of the script, and source any required env file from inside the script.

A useful diagnostic: add set -x to the top of the script, redirect output and error to a log file (>> /var/log/myjob.log 2>&1), and check the log after the next scheduled run. If the job did not run at all, the cron expression is wrong. If the job ran but produced errors, the command is wrong.

For Quartz and Spring, the equivalent of “run it by hand” is to invoke the underlying method directly, in a test, with the same arguments the scheduler will pass. The test confirms the method works; the scheduler is then just the timing mechanism.

How this fits the rest of the stack

A cron job that runs reliably is the difference between a team that knows what is happening in production and a team that finds out when a customer complains. The RunxBuild hosting calculator is the right place to model what scheduled jobs cost at the team’s actual usage — pick the runtime size, the schedule frequency, the storage for logs and output, and the bandwidth for any artifacts the jobs write, and the calculator shows what the platform actually costs.

Useful related references:

FAQ

What is the standard cron field order?

Minute, hour, day-of-month, month, day-of-week, command. Five fields, then a space, then the command. Anything that does not match this shape is not a standard Vixie cron expression.

What is the difference between 5-field and 6-field cron?

5-field is Vixie cron, the standard on Linux and macOS. 6-field adds a year at the end and is used by Quartz, Spring’s @Scheduled, and AWS EventBridge. Kubernetes CronJob and GitHub Actions use 5-field.

Why does 0 0 * * 7 work on Linux but not on Quartz?

Because Vixie cron allows 0-7 for the day-of-week with 0 and 7 both meaning Sunday, while Quartz uses 1-7 with 1 meaning Sunday. The expression 0 0 * * 7 means “midnight on Sunday” in Vixie cron and is out of range in Quartz.

Can I use the day name instead of the number?

Yes, in Vixie cron, Quartz, and Spring. 0 0 * * SUN means “midnight on Sunday” in all three. The day names (SUN, MON, TUE, WED, THU, FRI, SAT) are the same everywhere and are the portable choice.

What happens to cron jobs on the daylight saving transition?

A job scheduled for 2:30am on the spring-forward day will not run, because 2:30am does not exist. A job scheduled for 1:30am on the fall-back day will run twice. The fixes are to use UTC, schedule for a time outside the transition window, or use a scheduler with proper time-zone handling.

What is the difference between */15 and 0,15,30,45 in the minute field?

Nothing. */15 is shorthand for “every 15 minutes starting at 0,” which is the same set of minutes as 0,15,30,45. The shorthand is the right choice when the value is evenly divisible into 60.

How do I test a cron expression without waiting for it to run?

Use crontab.guru for a five-field expression, or the equivalent tool for your scheduler. crontab.guru describes the expression in plain English and shows the next 10 runs based on the current time. Then run the command by hand, in a non-interactive shell, with the same environment cron will have, to confirm the command itself works.

#Cron#Scheduling#Linux#Operations#DevOps