36

It is a famous "problem" that when a crontab line contains both day of week and day of month cron uses OR for figuring out a day to fire the command. E.g. if you write

* * 13 * 5 command

the command will execute on every Friday and every 13th day of month, not only on the Fridays that are 13th. This contradicts the format for the other fields (when you write 30 2 * * * it will be executed only when both - hour AND minute - are exactly what you specified; same for all other fields except for DoW and DoM when they are both specified).

So my question is: is there a specific reason for this exception? I mean, there should be a reason, but I can't seem to find it. (And instead I see a lot of people in the internets who would like for these fields to be treated like any other - with the "AND strategy", precisely for stuff like "Friday 13th" or "2nd Thursday of May".)

3 Answers3

19

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".

13

Maybe this won't be a deep enough "why" to satisfy you - it certainly doesn't satisfy me - but a shallow answer is "because the standard says so".

Specifically, the POSIX standard dictates at http://pubs.opengroup.org/onlinepubs/9699919799/utilities/crontab.html that:

if either the month or day of month is specified as an element or list, and the day of week is also specified as an element or list, then any day matching either the month and day of month, or the day of week, shall be matched

(bolding mine).

I have no idea why this is what the standard requires. Interestingly, it seems like even Paul Vixie, who implemented Vixie Cron (the Cron implementation used on both Ubuntu and MacOS) doesn't know either; in cron.c there's this comment:

/* the dom/dow situation is odd.  '* * 1,15 * Sun' will run on the
 * first and fifteenth AND every Sunday;  '* * * * Sun' will run *only*
 * on Sundays;  '* * 1,15 * *' will run *only* the 1st and 15th.  this
 * is why we keep 'e->dow_star' and 'e->dom_star'.  yes, it's bizarre.
 * like many bizarre things, it's the standard.
 */

So, by the sounds of it, even the implementer of the Cron you're probably using doesn't know the answer to your question in any more depth than the non-explanation I give in the first paragraph of this answer.

Mark Amery
  • 143,130
  • 81
  • 406
  • 459
  • Funny enough that implementation has its own issues due to ambiguity. The spec says "if either the month or day of month is specified as an element or list, and the day of week is also specified as an element or list, then any day matching either the month and day of month, or the day of week, shall be matched". Yet in that implementation "month" isn't considered in the calculation, just "day of month". Give it some time and the official spec will introduce this bug too. – roim May 23 '23 at 01:05
  • @roim Ugh. Good catch. What a dumb mess this all is. – Mark Amery May 23 '23 at 05:00
-3

I work on a Unix server that uses many scripts in the crontab. It is very convenient for us to be able to indicate specific dates on scripts that should run on a single day of the week. In my case, I can't see why I would run a scheduled script on a day of the week ONLY if it is on a 13th, taking your example.

AbysmalCode
  • 13
  • 1
  • 1
  • 5
  • 8
    Friday 13th is only to illustrate. More common is the desire to write something like `0 0 1-7 * 6` - "the first Saturday of the month" (that is if the crontab would execute the command only when both conditions are met). But, anyway, is there a case (or could you imagine one) where you would need use something like "run same script at all Nth days of month and at all Mth days of week" (which is how crontab works now)? – Alexander Shmidt Dec 19 '15 at 21:41
  • 5
    -1, for a couple of reasons. Firstly, it's unclear what you mean by *"It is very convenient for us to be able to indicate specific dates on scripts that should run on a single day of the week."* (indeed, that sounds like exactly the same thing that it *isn't* possible to do, and that you say you can't see the point of in your next sentence. Secondly, there are simple and common use cases for the behaviour that you *"can't see why"* anyone would want to have - such as the "first Saturday of the month" scenario described by @AlexanderShmidt above. – Mark Amery Sep 04 '18 at 14:17