I want to run a script every 23 hours. following syntax tried but its not working. is it right syntax for 23 hours:
<cron_expr>0 0,23,46,69,92,115 * * *</cron_expr>
I want to run a script every 23 hours. following syntax tried but its not working. is it right syntax for 23 hours:
<cron_expr>0 0,23,46,69,92,115 * * *</cron_expr>
You could do every 24 hours like this, every 23 hours would be a little trickier.
<cron_expr>0 23 * * *</cron_expr>
Technically the syntax for every something somethings would be */something, so */23 in your case.
Ie. If you wanted a cron to run every 6 hours, exactly on the hour, it would be,
<cron_expr>0 */6 * * *</cron_expr>
But this expression is only going to be valid for values under 12, as the cron's interpretation of 'every' resets each day.
So for every 23 hours, on the hour, you would be best executing it every hour like so, and doing a modulus of 23 within your script itself.
<cron_expr>0 * * * *</cron_expr>
Then in the method being executed, place this at the start,
$time = time();
if (((($time - ($time % 3600))/3600) % 23) != 0)
return;
*/23 and as suggested, it won't produce the desired results. So I've updated it with a complimentary PHP conditional statement.
– Ben Lessani
Jul 07 '15 at 22:21
If you want every 23 hours, the expression would be:
<schedule>00 */22 * * *</schedule>
This will execute at minute 0 past every 22nd hour.
But more suitable way is at every 24 hours, for that you can choose any of below expressions:
<schedule>0 23 * * *</schedule>
Or
<schedule>00 */23 * * *</schedule>
As suggested by Ben Lessani Sonassi, best approach is to cron your script every hour, and doing a modulus of 23 against current plain time (o'clock, eg for instance 03:00 when parsing time is inside range [03:00,03:59]) within your script itself to determine if process can be run.
But in order to run every 23 hours, you have to do a modulus 23*3600 against seconds elapsed since Unix epoch.
So, in order to run a process defined in main function every 23 hours, add shell script below to your crontab as 0 * * * *
#!/bin/bash
main() (
echo "it's time to run our process"
)
checkTimeRange() (
range hour parameter is required
rangeHour=${1:?Missing time range}
second parameter is optional, for unit testing
epochTime=${2:?$(date +%s)}
modulus returns the number of seconds elapsed since matching rangeHour
modulus=$(( epochTime % ( rangeHour * 3600 ) ))
check if modulus is inside a range of [ 00:00 - 59:59 ] minutes
eg. less than 3600 secondes
[[ ${modulus} -lt 3600 ]]
)
if checkTimeRange 23; then
current time matches the 23 hours period, let's start our stuff
main
fi
Under the hood
['Curious people only' mode on]
Purpose of checkTimeRange shell function is to check if the call is performed when current time modulus hourPeriod is inside a range 0:00 to 59:59 minutes, in order to be able to set up an hourly cron between 0 and 59 minutes.
For deeper explanations, consider 29 Jun 2021 04:15:59 PM UTC (the date I wrote this article), which represents 1624983359 seconds since epoch time:
> date -d '29 Jun 2021 04:15:59 PM UTC' +%s
1624983359
> date -d @1624983359
Tue 29 Jun 2021 04:15:59 PM UTC
This number of seconds minus its modulus against 23 hours gives the previous valid trigger time for a period of 23 hours :
> echo $(( 1624983359 - ( 1624983359 % ( 23*3600 ) ) ))
1624950000
> date -d @1624950000
Tue 29 Jun 2021 07:00:00 AM UTC
And next trigger time for a 23 hour period would be Wed 30 Jun 2021 06:00:00 AM UTC:
> echo $(( 1624950000 + ( 23 * 3600 ) ))
1625032800
> date -d @1625032800
Wed 30 Jun 2021 06:00:00 AM UTC
So checkTimeRange shell function would have to return true for times from Tue 29 Jun 2021 07:00:00 AM UTC to Tue 29 Jun 2021 07:59:59 AM UTC and Wed 30 Jun 2021 06:00:00 AM UTC to Wed 30 Jun 2021 06:59:59 AM UTC:
> date -d 'Tue 29 Jun 2021 07:00:00 AM UTC' +%s
1624950000
> checkTimeRange 23 1624950000 && echo OK || echo KO
OK
> date -d @1624949999
Tue 29 Jun 2021 06:59:59 AM UTC
> checkTimeRange 23 1624949999 && echo OK || echo KO
KO
> date -d 'Tue 29 Jun 2021 07:59:59 AM UTC' +%s
1624953599
> checkTimeRange 23 1624953599 && echo OK || echo KO
OK
> date -d @1624953600
'Tue 29 Jun 2021 08:00:00 AM UTC'
> checkTimeRange 23 1624953600 && echo OK || echo KO
KO
> date -d 'Wed 30 Jun 2021 06:00:00 AM UTC' +%s
1625032800
> checkTimeRange 23 1625032800 && echo OK || echo KO
OK
> date -d @1625032799
Wed 30 Jun 2021 05:59:59 AM UTC
> checkTimeRange 23 1625032799 && echo OK || echo KO
KO
> date -d 'Wed 30 Jun 2021 06:59:59 AM UTC' +%s
1625036399
> checkTimeRange 23 1625036399 && echo OK || echo KO
OK
> date -d @1625036400
Wed 30 Jun 2021 07:00:00 AM UTC
> checkTimeRange 23 1625036400 && echo OK || echo KO
KO
['Curious people only' mode off]
And, on top of that, some useful references:
This is the correct way:
<cron_expr>* */23 * * *</cron_expr>
0 at the minute position, but also not correct.
– Fabian Schmengler
Jul 07 '15 at 12:47