Skip to main content
DevOps
Published 6 min read

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 Friday

The 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 Friday

From 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

SchedulerBoth fields restrictedNotes
Unix/Linux cronEither field matches (OR)If one field starts with *, both must match.
Kubernetes CronJobEither field matches (OR)Uses the same star rule as Unix cron.
SpringBoth must match (AND)? and * both mean 'any'.
QuartzNot allowedExactly one field must be ?.
AWS EventBridgeNot allowedExactly 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.

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.

Buy me a byte 💾