Why a cron job runs on the wrong day
Last reviewed 30 October 2026
If both the day-of-month and the day-of-week are restricted, Vixie cron and cronie run the job when either field matches. They do not wait until both match. 0 9 1 * 5 is 09:00 on the 1st of every month, and also 09:00 every Friday. It is not “only when the 1st falls on a Friday.” Build the fields in the cron expression generator, then test the line on the host that will run it. The generator cannot know which daemon you have.
What “restricted” means
A star is not a restriction. It means “every,” so that field drops out of the choice.
0 9 1 * * runs at 09:00 on the 1st, and on no other day. The weekday is a star, so Friday does not matter.
0 9 * * 5 runs at 09:00 every Friday. The day of the month is a star, so the 1st does not matter unless the 1st is a Friday.
The either-day rule starts only when both day fields are restricted. A number, a list, a range, or a step such as 1-31/2 is restricted. In Vixie cron and cronie, a day field that starts with * counts as unrestricted, including */2. The step still selects days. Cron then combines that field with the other day field using AND, not OR. The usual crontab(5) example is:
30 4 1,15 * 5Read that as 04:30 on the 1st, 04:30 on the 15th, and 04:30 every Friday. On a Friday that is also the 1st, that is still one crontab line, so the command runs once that morning, not twice.
0 9 * * 1-5 is not this rule. The day-of-month is a star, so the line is simply weekdays at 09:00. The step schedules in every 5 minutes keep both day fields as stars, so they run every day.
Which cron this describes
This is the documented rule for Vixie cron and cronie, the implementations behind crontab on most Linux servers. If both day fields are restricted, the command runs when either one matches.
FreeBSD’s crontab(5) describes the same either-field rule. Confirm that man page on the version you run.
Check the CronJob docs for the Kubernetes version you run. This guide does not claim that every version uses the either-day rule.
Quartz uses six fields, or seven when a year is included. The first field is seconds, and one of the day fields is ?. Spring’s cron uses that six-field form. EventBridge also uses six fields, with no seconds field: minutes, hours, day-of-month, month, day-of-week, and year. One of its day fields is ? as well. A five-field line from this site matches neither shape. systemd timers use OnCalendar, which combines a weekday and a day of the month with AND, unlike cron. Mon *-*-01 09:00:00 is 09:00 only when the 1st is a Monday. Confirm it with systemd-analyze calendar on that machine before you install it.
This guide does not claim the either-day rule for GitHub Actions or BusyBox crond. Test those on their own docs.
On Vixie cron and cronie, Sunday is 0 and also 7. date +%w prints 0 for Sunday through 6 for Saturday. Run it on the server so you are looking at that clock.
How to test it on the host
Pick a weekday that is not the 31st. Suppose today is Wednesday the 15th, and date +%w prints 3.
* * 31 * 3 date >> /tmp/cron-or-test.logThe day-of-month is 31, which is not today. The day-of-week is 3, which is today. If a new line appears within a minute, this daemon is using the either-field rule: Wednesday was enough.
Then try the day-of-month alone:
* * 31 * * date >> /tmp/cron-or-test.logThat line should stay quiet today, because the weekday is a star and the date is not the 31st. Remove both lines when the test is done. A * in the minute field really does mean every minute, so do not leave the test in place.
If today is the 31st, swap 31 for a day number that is not today. The point is to make one field true and the other false, and see whether the command still runs.
How to require both days
You cannot say “Friday the 1st only” with one standard five-field line on Vixie cron. The line that looks like it (0 9 1 * 5) means the 1st or Friday.
Schedule one of the fields, and test the other in the command. This runs at 09:00 on the 1st, and continues only when date +%u says Friday. On GNU date, and in POSIX, %u is 1 for Monday through 7 for Sunday, so Friday is 5. Run date +%u once on that server anyway.
0 9 1 * * [ "$(date +\%u)" -eq 5 ] && /usr/local/bin/jobCron runs the command with sh. The [ test is a POSIX builtin, so it does not depend on bash. Use the absolute path of the job. Cron’s PATH is often too short to find a program by name.
The other direction fires on weekdays and continues only on the 1st. %d prints 01 through 31. The numeric test treats 01 as 1.
0 9 * * 1-5 [ "$(date +\%d)" -eq 1 ] && /usr/local/bin/jobIn crontab write \%, because a bare % is a newline. A terminal keeps %.
If you want the reader to see the “or” without remembering the rule, write two lines:
0 9 1 * * /usr/local/bin/job
0 9 * * 5 /usr/local/bin/jobOn Vixie cron that set of days matches 0 9 1 * 5, with one difference. When the 1st is a Friday, the two lines both match that minute, so the job runs twice. The single line runs once. If the work must happen once, keep one line and do the weekday test inside it.
Common questions
Does 0 9 1 * 1-5 mean weekdays that are also the 1st?
No, not on Vixie cron or cronie. Both day fields are restricted, so the job runs on the 1st, and it also runs every weekday.
Does a star turn the rule off?
A bare * does, and so does a field that starts with *, such as */2. 0 9 1 * * is the 1st only. 0 9 * * 5 is Friday only.
Does Sunday as 7 change the either-field rule?
No. 0 and 7 are two names for Sunday on Vixie cron. The either-field rule is about whether both day fields are restricted, not about which number you used for Sunday.
Can one crontab line run twice when both fields match?
No. One line is one command. On a Friday that is also the 1st, 0 9 1 * 5 matches once at 09:00 and runs once. Two separate lines can both match that minute and run twice.
What if the host is not cronie?
Do the one-minute test above. If * * 31 * 3 stays silent on a Wednesday that is not the 31st, that daemon is not using the either-field rule, and the workarounds in this guide are the wrong shape for it.