Why Day-of-Month and Day-of-Week Behave Differently in Cron
Why 0 0 13 * 5 is not 'Friday the 13th' in Unix cron, and how Spring, Quartz and EventBridge treat the same fields.
The two day fields in a cron expression look independent, but they are not. How they combine is one of the least intuitive parts of cron, and the rule changes from one scheduler to the next. An expression that behaves exactly as you expect in one place can run far more often, or far less often, in another.
Unix cron: either field matches
In Vixie-style Unix cron, if both day-of-month and day-of-week are restricted, a day matches when either of them matches. So this expression is not 'Friday the 13th':
0 0 13 * 5 # midnight on the 13th of every month AND on every FridayThe word 'and' in that comment means 'both kinds of day count', not 'both conditions must hold'. In October 2026 it fires on the 2nd, 9th, 13th, 16th, 23rd and 30th: all five Fridays plus the 13th, which falls on a Tuesday.
There is a subtle exception. If either day field begins with an asterisk, the rule flips to 'both must match', and the restricted field effectively decides. That includes stepped asterisks, so */2 in the day-of-month field counts as 'starting with *'. The expression 0 0 */2 * 1 therefore matches Mondays that fall on odd-numbered days, not every Monday plus every other day.
Spring: both must match
Spring's cron support evaluates every field, so a day matches only when both the day-of-month and the day-of-week match. The same fields written for Spring really do mean Friday the 13th:
0 0 0 13 * 5 # Spring: midnight only when the 13th is a FridayFrom October 2026 the next matches are 13 November 2026 and 13 August 2027.
Quartz and EventBridge: one of them must be ?
Quartz and AWS EventBridge avoid the question. Exactly one of the two day fields must be ?, meaning 'no specific value', and the other field alone chooses the days. Setting both is rejected rather than interpreted.
0 0 12 ? * MON-FRI # Quartz: weekdays
0 0 12 15 * ? # Quartz: the 15th of each month
0 0 12 * * MON-FRI # rejected by Quartz: neither field is ?Summary
| Scheduler | Both fields restricted | Notes |
|---|---|---|
| Unix/Linux cron | Either field matches (OR) | If one field starts with *, both must match. |
| Kubernetes CronJob | Either field matches (OR) | Uses the same star rule as Unix cron. |
| Spring | Both must match (AND) | ? and * both mean 'any'. |
| Quartz | Not allowed | Exactly one field must be ?. |
| AWS EventBridge | Not allowed | Exactly one field must be ?. |
Check before you move a schedule between systems
Copying 0 0 13 * 5 from a crontab into a Spring annotation (after adding a seconds field) silently changes it from 'every Friday and every 13th' to 'only Friday the 13th'.
Working around it
- To get 'AND' in Unix cron, schedule on one field and test the other in the job, for example run on the 13th and exit unless the weekday is Friday.
- To get 'OR' in Spring or Quartz, define two schedules.
- Prefer weekday names so the weekday part is never misread through numbering differences.
The Cron Builder on DevCraftKit applies the rule of the dialect you select, explains in plain English how the two day fields interact for your expression, lists the matching dates, and warns when switching dialect changes the upcoming run times.
Conclusion
Whenever an expression restricts both day fields (see also five-field vs. six-field cron), stop and look up your scheduler's rule. The same text can mean a union in one place, an intersection in another, and an error in a third.
Frequently asked questions
- Does cron combine day-of-month and day-of-week with AND or OR?
- In Vixie-style Unix cron, when both fields are restricted and neither starts with *, a day matches if either field matches. If one of them starts with *, both must match, so the restricted field decides. Other dialects use different rules.
- How do I run a job only on Friday the 13th?
- Unix cron cannot express it directly because it would match every 13th and every Friday. Schedule the 13th and check the weekday inside the job, or use a dialect such as Spring that requires both day fields to match.
- Why does Quartz need a question mark?
- Quartz does not support applying both day fields, so it requires one of them to be ?, meaning no specific value. The other field alone decides the days.
Try it yourself
The tool that pairs with this guide.
Did this help you sort out your server configuration?
If these free developer tools save you time, consider buying me a byte. Your support helps keep DevCraftKit free and growing.
Related articles
What Is .htaccess? A Practical Guide for Apache Sites
A per-directory configuration file for Apache: what it can do, where it stops working, and how to avoid the usual mistakes.
Published
Apache Rewrite Rules Explained: RewriteRule, RewriteCond and Flags
Understand how RewriteRule and RewriteCond fit together, what the flags do, and why per-directory rules behave differently.
Published
Cron Syntax Explained: A Complete Guide to Cron Expressions
What each cron field means, how ranges and steps are matched, and how to read an expression without guessing.
Published