4

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>
3
  • 2
    cronwtf.github.io
    – user2857
    Jul 6, 2015 at 9:55
  • 1
    No, the second number is the hour of the day. AFAIK what you want is not possible with cron expressions. Jul 6, 2015 at 10:28
  • 1
    If you would explain why you need this and for what then maybe we can advise you any alternatives or give you alternative ideas.
    – 7ochem
    Jul 6, 2015 at 10:41

4 Answers 4

6

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;
3
  • This will execute the job every day at 23:00, since 23 is the only hour of the day divisibly by 23 Jul 7, 2015 at 12:47
  • That's why I gave a few examples and said technically. I can't say I've ever tried to run something on such an irregular schedule. Jul 7, 2015 at 13:05
  • I've tested the behaviour of */23 and as suggested, it won't produce the desired results. So I've updated it with a complimentary PHP conditional statement. Jul 7, 2015 at 22:21
0

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>

Check for more expressions

0

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:

-4

This is the correct way:

<cron_expr>* */23 * * *</cron_expr>
4
  • This will execute the job every day from 23:00 til 23:59 every minute. (23 is the only hour of the day divisibly by 23) Jul 6, 2015 at 10:27
  • Why my answer is incorrect and the answer by Ben is correct.. i cant understand.. Jul 7, 2015 at 12:45
  • It is less wrong because of the 0 at the minute position, but also not correct. Jul 7, 2015 at 12:47
  • my fault.. i didnt see the initiial zero in ben answer!!!! :) thx Jul 7, 2015 at 12:48

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.