Cron Expression: First Monday of the Month
There is no single cron field for “first Monday.” The reliable pattern is to run every Monday and skip unless the date is within the first week. Below is the correct expression, plus the common 0 9 1-7 * 1 mistake that fires far too often.
Why cron can't express it directly
Cron matches on calendar fields, not “the Nth weekday.” Vixie cron (the default on Linux) has no L or # operators like Quartz does, so “first Monday” has to be built from a weekday schedule plus a date check.
The pitfall: 0 9 1-7 * 1
It is tempting to write 0 9 1-7 * 1 (“days 1–7, on Monday”). But Vixie cron uses OR when both day-of-month and day-of-week are restricted: this fires on every day 1–7 and every Monday all month — not their intersection. It runs about 11 times a month, not once.
The correct pattern
Schedule every Monday at 9:00 and gate on the day of month in the script:
0 9 * * 1 in cron, then: [ "$(date +%d)" -le 07 ] || exit 0. The first Monday is always the only Monday whose date is 7 or lower, so this fires exactly once per month.
If you use Quartz (Java/Spring)
Quartz supports the # operator: 0 0 9 ? * MON#1 means the first Monday at 9:00 directly — no script gate needed.
FAQ
Can standard cron do 'first Monday of the month'?
Not in one line. Vixie cron has no Nth-weekday operator, so you run every Monday (0 9 * * 1) and skip in the script unless the date is 7 or lower.
Why is 0 9 1-7 * 1 wrong?
When both day-of-month and day-of-week are restricted, Vixie cron ORs them, so it runs on every day 1–7 and on every Monday — roughly 11 times a month instead of once.
What is the Quartz equivalent?
0 0 9 ? * MON#1 — Quartz's # operator selects the first Monday directly.