The Cron Fields, In Order

Standard (Vixie) cron β€” the version used by Linux crontab, most CI/CD schedulers, and Kubernetes CronJobs β€” has exactly 5 whitespace-separated fields:

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ minute (0-59)
β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ hour (0-23)
β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€ day of month (1-31)
β”‚ β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€ month (1-12)
β”‚ β”‚ β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€ day of week (0-6, 0 = Sunday)
β”‚ β”‚ β”‚ β”‚ β”‚
* * * * *

Some schedulers β€” most notably Quartz (used by Spring Boot's @Scheduled and many Java job runners) β€” add a sixth leading field for seconds (0-59), shifting everything one position to the right. Kubernetes CronJobs and standard Linux crontab never use a seconds field; if you see 6 fields, you're almost certainly looking at Quartz syntax.

Special Characters

  • * β€” "every value." * * * * * means every minute, of every hour, of every day.
  • , β€” a list. 0,15,30,45 * * * * means at minutes 0, 15, 30, and 45 of every hour.
  • - β€” a range. 9-17 * * * * means every minute during the hours 9 through 17 (9am–5pm).
  • / β€” a step value, used with a range or *. */15 * * * * means every 15 minutes; 0 0-23/6 * * * means at minute 0 every 6 hours.
  • ? β€” "no specific value," used only in Quartz syntax in the day-of-month or day-of-week field when the other is set, since Quartz doesn't support both fields being restricted simultaneously.
  • L β€” "last," a Quartz-only character. In the day-of-month field, L means the last day of the month; in day-of-week, 6L means the last Friday of the month.
  • W β€” "nearest weekday," Quartz-only. 15W in the day-of-month field means the nearest weekday to the 15th.
  • # β€” "the Nth occurrence," Quartz-only. MON#1 means the first Monday of the month.

Standard Cron vs Quartz/Spring Cron

These two dialects look similar but are not interchangeable, and pasting a standard cron expression into a Quartz scheduler (or vice versa) is a common source of silent scheduling bugs.

FeatureStandard CronQuartz / Spring Cron
Number of fields56 or 7 (seconds field added; year is optional)
Day-of-week range0-6 (0 = Sunday)1-7 (1 = Sunday) or names SUN-SAT
Day-of-month + day-of-week both restrictedAllowed β€” treated as ORNot allowed β€” one must be ?
Extra charactersMostly just * , - /Also supports L, W, #, ?
Typical useLinux crontab, Kubernetes CronJob, GitHub ActionsSpring @Scheduled, Java Quartz library, Jenkins (partial)

Common Gotchas

  • Day-of-month and day-of-week are OR'd, not AND'd, in standard cron. 0 9 1 * MON runs at 9am on the 1st of every month and every Monday β€” not only on Mondays that happen to be the 1st. If you actually want "the 1st, but only if it's a Monday," you need application logic, not cron alone.
  • Both 0 and 7 mean Sunday in standard cron's day-of-week field in most implementations (Vixie cron), which causes confusion when porting expressions between systems that only accept one or the other.
  • Timezone handling is scheduler-specific, not cron-specific. Cron syntax itself has no timezone concept β€” it's entirely up to the runner. Linux crontab uses system local time unless CRON_TZ is set; Kubernetes CronJobs use the kube-controller-manager's timezone unless a timeZone field is set (supported since Kubernetes 1.27); cloud schedulers like AWS EventBridge Scheduler require an explicit timezone parameter.
  • "Every 5 minutes" using /5 is anchored to 0, not to whenever the job was created. */5 * * * * fires at :00, :05, :10... not 5 minutes after deployment. This surprises people who expect step values to be relative to "now."
  • Skipped or duplicate runs around DST transitions are a real risk for any cron field expressed in local time β€” a job scheduled for 2:30am may not run at all on the "spring forward" day, or may run twice on "fall back," depending on the scheduler's DST handling.
⏰

DevOpsArsenal Cron Explainer

Paste any cron expression and get a plain-English explanation plus the next several run times β€” instantly, in your browser, no signup required.

Try Cron Explainer Free β†’

Real-World Examples

Cron ExpressionMeaning
*/15 * * * *Every 15 minutes (at :00, :15, :30, :45)
0 9 * * 1-5Every weekday (Mon–Fri) at 9:00am
0 0 1 * *At midnight on the 1st of every month
0 */6 * * *Every 6 hours, on the hour (00:00, 06:00, 12:00, 18:00)
0 9 * * MON#1 (Quartz)9:00am on the first Monday of the month
0 2 * * 0Every Sunday at 2:00am (off-peak backup window)
30 23 * * *Every day at 11:30pm
0 0 L * ? (Quartz)Midnight on the last day of every month
*/5 9-17 * * 1-5Every 5 minutes, but only 9am–5pm, Monday through Friday
0 0 1 1 *Midnight on January 1st β€” once a year

Frequently Asked Questions

What are the 5 fields in a cron expression? β–Ό
Standard cron has 5 fields, in order: minute (0-59), hour (0-23), day of month (1-31), month (1-12), and day of week (0-6, where 0 is Sunday). Some schedulers, like Quartz used in Spring and Java applications, add a 6th leading field for seconds, making the first field range 0-59 for seconds before minute.
Why does my cron job run on both the day-of-month and day-of-week I specified? β–Ό
When both the day-of-month and day-of-week fields are restricted (not set to *), standard cron treats them as an OR condition, not AND β€” the job runs if either condition matches. For example, 0 9 1 * MON runs at 9am on the 1st of the month AND every Monday, not only on Mondays that fall on the 1st.
Does cron use the server's timezone or UTC? β–Ό
It depends entirely on the scheduler. Traditional crontab on Linux uses the system's local timezone by default, unless a CRON_TZ environment variable is set in the crontab file. Cloud schedulers vary: AWS EventBridge Scheduler and GCP Cloud Scheduler let you specify a timezone explicitly, while some legacy systems default to UTC. Always check your specific platform's documentation rather than assuming.
What is the difference between standard cron and Quartz cron syntax? β–Ό
Quartz cron, used by Java schedulers and Spring Boot's @Scheduled annotation, adds a seconds field at the start and uses 1-7 for day-of-week (1 = Sunday) instead of standard cron's 0-6 (0 = Sunday). Quartz also requires that either day-of-month or day-of-week be a question mark (?) rather than both being asterisks, since Quartz does not support the OR-matching behavior standard cron uses when both fields are restricted.
Cron syntax has stayed nearly unchanged since the 1970s because it's compact and expressive once you know the field order. The biggest source of production incidents isn't the syntax itself β€” it's assuming behavior that doesn't hold across implementations: timezone defaults, the day-of-month/day-of-week OR logic, and Quartz's extra characters. When in doubt, paste the expression into a cron explainer and check the next few run times before you deploy it.