Why crontab uses OR when both day of month and day of week specified?

Going back a step further from Vixie cron, the “wday OR mday” logic was present in System V cron, but not System III or anything earlier.

Before Paul Vixie wrote his cron replacement, BSD cron was like the SysIII-and-earlier cron. All 5 fields were ANDed. The post-4.4 BSDs adopted Vixie cron, making themselves more SysV-like.

So don’t ask (blame) Vixie. He was just cloning SysV.

Why did SysV do that? I don’t know but I’ll try to provide some partial clues…

To try to understand what happened in SysV, it helps to look at the source (before – SysIII and after – SVr4) and also the documentation of the new behavior:

Note: the specification of days may be made by two fields (day of the month and day of the week). If both are specified as a list of elements, both are adhered to.

(Excerpt from SunOS 4.1.3 man page. It appears to be SysV-ish in this area. BSD cron never had this behavior before Paul Vixie wrote his replacement.)

“Both are adhered to” is a confusing substitute for a normal boolean expression using ANDs and ORs. It’s still there in the OpenSolaris man page a couple of decades later:

The specification of days can be made by two fields (day of the month and day of the week). Both are adhered to if specified as a list of elements.

The SysV code is a complete rewrite. One of its features is that it sleeps for a long time when no jobs are due to run soon. (The older cron wakes up every minute and compares the current time to all job specifications.) A comment at the top of the calculation function (next_time) explains: NOTE: this routine is hard to understand.

It is indeed hard to understand. It is a “find next execution time for this crontab line” function, instead of a “decide whether the current time matches this crontab line” function, so it takes some effort to even figure out that the matching rule implicit in this function, when both mday and wday are non-*, is (month AND hour AND minute AND (mday OR wday)).

Based on that, combined with the way the documentation avoids explicitly telling us the boolean relationship between mday matching and wday matching, I’m going to guess that the person who wrote the new cron just wasn’t thinking about it in those terms. They were thinking not about a combination of 5 booleans (corresponding directly to 5 fields in a struct tm), but about a set of 4 questions:

  1. Is it the correct month?
  2. Is it the correct day?
  3. Is it the correct hour?
  4. Is it the correct minute?

This leads naturally to the day comparisons being combined in their own way before ANDing everything else together. Maybe the SysV cron author just did what felt like the obvious thing at the time, without checking for compatibility with the old cron or pondering use cases like “first Saturday of every month”.

Leave a Comment