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>
Amit Bera
  • 77,456
  • 20
  • 123
  • 237
Sivakumar K
  • 2,013
  • 9
  • 27
  • 43

4 Answers4

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;
Ben Lessani
  • 17,630
  • 4
  • 44
  • 68
  • This will execute the job every day at 23:00, since 23 is the only hour of the day divisibly by 23 – Fabian Schmengler Jul 07 '15 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. – Ben Lessani Jul 07 '15 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. – Ben Lessani Jul 07 '15 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

Ajwad Syed
  • 1,591
  • 25
  • 61
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>
nino.aratari
  • 139
  • 1
  • 1
  • 8