ShareYourGroupShareYourGroupCron Helper

Cron step values: why */45 does not mean every 45 minutes

The slash looks like "every n", but it only counts inside one field. That small difference causes many wrong schedules.

What a step does

*/n takes the values of the field in order, starting at the first value, and keeps every nth one. In the minute field the values are 0 to 59, so */10 is 0, 10, 20, 30, 40, 50. In the hour field the values are 0 to 23, so */6 is 0, 6, 12, 18. In the month field they are 1 to 12, so */3 is 1, 4, 7, 10: January, April, July and October. The cron manual explains it like this: steps are evaluated just within the field they are applied to.

You can put a step after a range as well. 9-17/2 in the hour field is 9, 11, 13, 15, 17, and 0-23/2 is 0, 2, 4, and so on up to 22. The manual even shows that the older, longer way of writing every second hour is the list 0,2,4,6,8,10,12,14,16,18,20,22.

Where it goes wrong

Because the count restarts with each hour (or day, or year), a step that does not divide the field's size evenly gives uneven gaps. The manual's own example: */23 in the hours field means to run on hour 0 and hour 23 of the calendar day, which is not "every 23 hours". The same applies to minutes. The expression */35 * * * * does not run every 35 minutes: it runs twice an hour, at minute 0 and minute 35, so the gaps are 35 minutes and then 25 minutes.

ExpressionReal runsGaps
*/20 * * * *0, 20, 4020, 20, 20: even, because 20 divides 60
*/25 * * * *0, 25, 5025, 25, then 10 into the next hour
*/45 * * * *0, 4545, then 15
0 */5 * * *hours 0, 5, 10, 15, 205, 5, 5, 5, then 4
0 */7 * * *hours 0, 7, 14, 217, 7, 7, then 3

The numbers that give an even gap are the divisors of the field size: for minutes 1, 2, 3, 4, 5, 6, 10, 12, 15, 20, 30 and 60; for hours 1, 2, 3, 4, 6, 8, 12 and 24.

If you need a true "every 45 minutes"

The manual's suggestion is to let cron start the job every minute and let a small test in the command decide. It gives a line that runs every 58 minutes, and the same idea gives every 45: a test on the Unix time in minutes. The line below runs the job when the number of minutes since 1 January 1970 divides by 45.

* * * * * [ $(( $(date +\%s) / 60 \% 45 )) -eq 0 ] && /home/me/bin/job.sh

Both percent signs carry a backslash, because cron treats an unescaped percent sign as a newline. This counts real time, so it ignores clock changes, but the runs are no longer aligned with the top of the hour. If the exact moment does not matter, picking 30 or 60 minutes is simpler and easier to explain to the next person.

The start-plus-step form

GitHub documents a form like 20/15 * * * *: start at minute 20 and run every 15 minutes through 59, which gives minutes 20, 35 and 50. Quartz accepts it too. The cron manual does not list it for ordinary crontabs, so on a Linux server write the range out as 20-59/15, which means the same thing and is understood everywhere.

Does */1 mean anything?

It means every value, the same as a plain star.

Can a step be larger than the field?

*/70 in the minute field would take only minute 0. Most programs accept it, but it is confusing: write 0.

This is an independent guide and tool. It is not connected with crontab.guru, Quartz, GitHub, Kubernetes, Spring or the Linux projects named here. Product names belong to their owners.