In Crontab generic way to specify every n mins where n > 60 [duplicate]

In crontab, i have seen a couple of answers where users have requested a way to run every 5 mins:

``````*/5 * * * * command
``````

Or every 5 mins with an offset:

``````10-59/5 * * * * command
``````

An i have seen some creative solutions where people have made 2 line crontabs for every 90 mins:

``````0 0-21/3 * * * whatever
30 1-22/3 * * * whatever
``````

Thanks to one of the answers below (thanks @khaled), here is another creative solution to 3h30mins:

``````0 0-23/7 * * * whatever
30 3-23/7 * * * whatever
``````

Is there a generic solution to the every x mins problem? For example I currently need every 3h30m.

To address the duplicate tag: The question linked is clearly different - there is general advice on how to setup and debug cron jobs. I am referring to a specific problem where we are reaching the limits of the cron syntax. I am looking for a general algorithm for solving the "every greater than 60 mins" problem, which is not addressed in the linked question.

• @JennyD and where in that question/answer does it describe the mathematical strategy behind setting up intervals not directly supported by the configuration? Having a canonical question about a command is not justification for blindly closing questions about usage not covered by that post. Jun 20, 2017 at 19:59
• @Kevin That would be fairly far down on the page, in the answer titled "Uncommon and irregular schedules". HTH, HAND. Jun 21, 2017 at 5:24

You just need to do the math yourself to come up with the required jobs that to achieve your timing.

``````0 0-23/7 * * * whatever
30 3-23/7 * * * whatever
``````

A simple algorithm can be concluded from these two examples (when having 30 minutes offset):

• Add two entries: one with 0 minutes offset and another with 30 minutes offset.
• Specify hours range width equals to `duration * 2`.
• Specify hours offset: one starts with 0, and the other starts with duration after discarding 30-minute part.

If you think more, you can come up with similar solutions for something like every 75 minutes.

Edit:

Cron can not be used for all types of scheduled jobs. For example, executing a job once per month on the last day of month. You can not simply do it with cron because the last day of month changes from month to another. To solve this, you can run a cron job in the possible range of values of last day of month (28-31) and verify it is really the last day or not in the script before doing the actual job.

• doing the math manually leads me to the same answer as yours given above for 3h30 mins (except it runs 30mins too early on the next day) Jun 20, 2017 at 8:29
• The algorithm you are building is actually what I'm looking for, a way to make crontab work for any x number of mins, that i can bookmark and refer to in future Jun 20, 2017 at 8:30
• @user230910 The solution for the general case is to not use cron for things it doesn't do well. Jun 20, 2017 at 8:40
• There is no sensible generic way of doing it in cron; if the time span isn't a whole fraction of a day, there isn't a way of doing it. For example, you might decide to create a line for every exception, as per examples above. If you apply this logic to a time span of 23:59, you would have to create at least 1440 lines (24hr*60min/hr)
– Pak
Jun 20, 2017 at 8:42
• I'd also suggest considering systemd timers, which can serve as a cron replacement while being far more flexible (and, yes, it can do last day of month, though only very recent versions as of 2017).
– Bob
Jun 20, 2017 at 11:39

Put the result of the command

``````date +%s
``````

in a variable in your crontab. Something like TIME=1497950105. Now in your crontab you need an entry like

``````* * * * * /bin/bash -c '[[ \$((\$(date +\%s)-TIME)) -gt seconds ]] && TIME=\$(date +\%s) && whatever'
``````

Where seconds is the number of seconds you want (12600 in your case ).

Or if you want to wait 3 hours and 30 minutes after the completion of the program

``````* * * * * /bin/bash -c '[[ \$((\$(date +\%s)-TIME)) -gt seconds ]] && whatever && TIME=\$(date +\%s)'
``````

Edit: I corrected my prevoius answer:

• you have to escape % sign with \, so %s becomes \%s
• you have to precede the command with /bin/bash -c

Another solution (without using TIME) is:

`````` * * * * * /bin/bash -c '[[ \$(((\$(date +\%s) / 60) % minutes)) -eq 0 ]] && whatever'
``````

Where minutes is 210 in your case.

Edit 2:

As suggested by MSalters it's better to run the entry every N minutes, where N is the greatest common divisor between 60 and your time interval in minutes

• how is TIME reset at the 211 second ? Jun 20, 2017 at 9:43
• VERY interesting! So you are running the job every min, and then doing a calculation to decide if it should actually run.. Jun 20, 2017 at 9:48
• would this deal with server restarts correctly? Jun 20, 2017 at 9:50
• After the first execution of the entry after the restart (it could be before 3 hours and 30 minutes) it will be correctly executed every 3 hours and 30 minutes. Jun 20, 2017 at 10:03
• Of course it's more efficient to run the test every 30 minutes. No point in checking the other 96.67% of cases. Granted, if the greatest common divider of your interval and 60 is 1, then this won't help. GCD(270,60) is 30, though. Jun 20, 2017 at 14:26

In this case I think you're simply trying to use the cron to do something it is not capable of doing by itself (of course excepting the solutions where cron actually executes a helper script periodically, in which case I'd argue it's not cron itself solving the problem).

The solution with the 3 hour 30 minute interval is not entirely correct. This was the given solution:

``````0 0-23/7 * * * whatever
30 3-23/7 * * * whatever
``````

The reason this is wrong is because cron will then run the job at the times 21:00 and 00:00, which is an interval of 3 hours rather than 3 hours 30 minutes.

A general solution for all time intervals would have to be able to handle cases that do not evenly divide into 24 hours. While it does not divide evenly into 24 hours, it does divide evenly into a week! The easiest way of thinking of this is to do two overlapping sets of "every 7 hours", like this:

``````0 0-23/7 * * 1 whatever
0 4-23/7 * * 2 whatever
0 1-23/7 * * 3 whatever
0 5-23/7 * * 4 whatever
0 2-23/7 * * 5 whatever
0 6-23/7 * * 6 whatever
0 3-23/7 * * 7 whatever
30 3-23/7 * * 1 whatever
30 0-23/7 * * 2 whatever
30 4-23/7 * * 3 whatever
30 1-23/7 * * 4 whatever
30 5-23/7 * * 5 whatever
30 2-23/7 * * 6 whatever
30 6-23/7 * * 7 whatever
``````

Something being divisible by a week is the best you can do, because months do not line up perfectly with weeks, and that's the only way it's doable. For example, an interval of precisely every 12 minutes is trivial in one line of crontab, but an interval of precisely every 11 minutes is impossible, because 10080 is not divisible by 11. (10080 being the number of minutes in a week).

It would definitely be possible to write an algorithm to solve the cases where this is possible, but it's clearly not worth very much, especially considering what the solutions would actually look like.

• thanks so much for the effort you put into this - it makes sense to me. Jun 21, 2017 at 10:05
• it seems that it is possible to come up with an algortihm to calculate lists of crontab lines that work nicely in divide into hour/day/week and even though this is a 14 line monster, its still trivial if it was generated by a tool Jun 21, 2017 at 10:06