[cron] Cron job every three days

Is it possible to run a cronjob every three days? Or maybe 10 times/month.

This question is related to cron

The answer is


If you want it to run on specific days of the month, like the 1st, 4th, 7th, etc... then you can just have a conditional in your script that checks for the current day of the month.

I thought all you needed for this was instead of */3 which means every three days, use 1/3 which means every three days starting on the 1st of the month. so 7/3 would mean every three days starting on the 7th of the month, etc.


I don't think you have what you need with:

0 0 */3 * * ## <<< WARNING!!! CAUSES UNEVEN INTERVALS AT END OF MONTH!!

Unfortunately, the */3 is setting the interval on every n day of the month and not every n days. See: explanation here. At the end of the month there is recurring issue guaranteed.

1st  at 2019-02-01 00:00:00
then at 2019-02-04 00:00:00 << 3 days, etc. OK
then at 2019-02-07 00:00:00
...
then at 2019-02-25 00:00:00
then at 2019-01-28 00:00:00
then at 2019-03-01 00:00:00 << 1 day WRONG
then at 2019-03-04 00:00:00
...

According to this article, you need to add some modulo math to the command being executed to get a TRUE "every N days". For example:

0 0 * * *  bash -c '(( $(date +\%s) / 86400 \% 3 == 0 )) && runmyjob.sh

In this example, the job will be checked daily at 12:00 AM, but will only execute when the number of days since 01-01-1970 modulo 3 is 0.

If you want it to be every 3 days from a specific date, use the following format:

0 0 * * *  bash -c '(( $(date +\%s -d "2019-01-01") / 86400 \% 3 == 0 )) && runmyjob.sh

You should learn the basics of crontab.

Edit the cron by command crontab -e and then ^ (CTRL) + X then Y and finally press ENTER (return) on mac to save the file. You can check the new crons have been installed of not by crontab -l

A crontab file has five fields for specifying mins, hours, the day of the month, month, and the day of the week followed by the command to be run at that interval.

*     *     *   *    *   command to be executed
-     -     -   -    -
|     |     |   |    |
|     |     |   |    +----- day of week (0-6) (Sunday=0)
|     |     |   +------- month (1-12)
|     |     +--------- day of month (1-31)
|     +----------- hour (0-23)
+------------- min (0-59)

* in the value field above means all legal values as in braces for that column.

Here, I wrote a detailed post about it: Setup Cron in Unix


0 0 * * * [ $(($((date +%-j- 1)) % 3)) == 0 ] && script

Get the day of the year from date, offset by 1 to start at 0, check if it is modulo three.


How about:

00 00  *  *   * every 3 days && echo test

Where every is a script:

#!/bin/sh

case $2 in
    days)
        expr `date +%j` % $1 = 0 > /dev/null
        ;;

    weeks)
        expr `date +%V` % $1 = 0 > /dev/null
        ;;

    months)
        expr `date +%m` % $1 = 0 > /dev/null
        ;;
esac

So it runs every day.

Using */3 runs on the 3rd, 6th, ... 27th, 30th of the month, but is then wrong after a month has a 31st day. The every script is only wrong after the end of the year.


I am not a cron specialist, but how about:

0 */72 * * *

It will run every 72 hours non-interrupted.

https://crontab.guru/#0_/72___


It would be simpler if you configured it to just run e.g. on monday and thursdays, which would give it a 3 and 4 day break.

Otherwise configure it to run daily, but make your php cron script exit early with:

if (! (date("z") % 3)) {
     exit;
}

* * */3 * *  that says, every minute of every hour on every three days. 

0 0 */3 * *  says at 00:00 (midnight) every three days.

0 0 1-30/3 * *

This would run every three days starting 1st. Here are the 20 scheduled runs -

  • 2015-06-01 00:00:00
  • 2015-06-04 00:00:00
  • 2015-06-07 00:00:00
  • 2015-06-10 00:00:00
  • 2015-06-13 00:00:00
  • 2015-06-16 00:00:00
  • 2015-06-19 00:00:00
  • 2015-06-22 00:00:00
  • 2015-06-25 00:00:00
  • 2015-06-28 00:00:00
  • 2015-07-01 00:00:00
  • 2015-07-04 00:00:00
  • 2015-07-07 00:00:00
  • 2015-07-10 00:00:00
  • 2015-07-13 00:00:00
  • 2015-07-16 00:00:00
  • 2015-07-19 00:00:00
  • 2015-07-22 00:00:00
  • 2015-07-25 00:00:00
  • 2015-07-28 00:00:00

Because cron is "stateless", it cannot accurately express "frequencies", only "patterns" which it (apparently) continuously matches against the current time.

Rephrasing your question makes this more obvious: "is it possible to run a cronjob at 00:01am every night except skip nights when it had run within 2 nights?" When cron is comparing the current time to job request time patterns, there's no way cron can know if it ran your job in the past.

(it certainly is possible to write a stateful cron that records past jobs and thus includes patterns for matching against this state, but that's not the standard cron included in most operating systems. Such a system would get complicated by requiring the introduction of the concept of when such patterns "reset". For example, is the pattern reset when the time is changed (i.e. the crontab entry is revised)? Look to your favorite calendar app to see how complicated it can get to express Repeating patterns of scheduled events, and note that they don't have the reset problem because the starting calendar event has a natural "start" a/k/a "reset" date. Try rescheduling an every-other-week recurring calendar event to postpone by a week, over christmas for example. Usually you have to terminate that recurring event and restart a completely new one; this illustrates the limited expressivity of how even complicated calendar apps represent repeating patterns. And of course Calendars have a lot of state-- each individual event can be deleted or rescheduled independently [in most calendar apps]).

Further, you probably want to do your job every 3rd night if successful, but if the last one failed, to try again immediately, perhaps the next night (not wait 3 more days) or even sooner, like an hour later (but stop retrying upon morning's arrival). Clearly, cron couldn't possibly know if your job succeeded and the pattern can't also express an alternate more frequent "retry" schedule.

ANYWAY-- You can do what you want yourself. Write a script, tell cron to run it nightly at 00:01am. This script could check the timestamp of something* which records the "last run", and if it was >3 days ago**, perform the job and reset the "last run" timestamp.

(*that timestamped indicator is a bit of persisted state which you can manipulate and examine, but which cron cannot)

**be careful with time arithmetic if you're using human-readable clock time-- twice a year, some days have 23 or 25 hours in their day, and 02:00-02:59 occurs twice in one day or not at all. Use UTC to avoid this.