Time remaining for the next run

cron doesn't know when a job is going to fire. All it does is every minute, go over all the crontab entries and fire those that match "$(date '+%M %H %d %m %w')".

What you could do is generate all those timestamps for every minute from now to 49 hours from now (account for DST change), do the matching by hand (the tricky part) and report the first matching one.

Or you could use the croniter python module:

python -c '
from croniter import croniter
from datetime import datetime
iter = croniter("3 9 * * *", datetime.now())
print iter.get_next(datetime)'

For the delay:

$ faketime 13:52:00 python -c '
from croniter import croniter
from datetime import datetime
d = datetime.now()
iter = croniter("30 9 * * *", d)
print iter.get_next(datetime) - d'
19:37:59.413956

Beware of potential bugs around DST changes though:

$ faketime '2015-03-28 01:01:00' python -c '
from croniter import croniter
from datetime import datetime
iter = croniter("1 1 * * *", datetime.now())
print iter.get_next(datetime)'
2015-03-29 02:01:00

$ FAKETIME_FMT=%s faketime -f 1445734799 date
Sun 25 Oct 01:59:59 BST 2015
$ FAKETIME_FMT=%s faketime -f 1445734799  python -c '
from croniter import croniter
from datetime import datetime
iter = croniter("1 1 * * *", datetime.now())
print iter.get_next(datetime)'
2015-10-25 01:01:00

$ FAKETIME_FMT=%s faketime -f 1445734799 python -c '
from croniter import croniter
from datetime import datetime
d = datetime.now()
iter = croniter("1 1 * * *", d)
print iter.get_next(datetime) - d'
-1 day, 23:01:01

cron itself takes care of that by avoiding to run the job twice if the time has gone backward, or run skipped jobs after the shift if the time has gone forward.


As it happens the %T format of the printf builtin of the ksh93 shell does support crontab specifications as input.

$ ksh93 -c 'printf "%(%F %T)T\n" now "30 9 * * *"'
2017-11-07 17:06:41
2017-11-08 09:30:00

So you can get the delta in seconds there with:

#! /bin/ksh93
crontab_line='30 9 * * *'
delta=$(($(printf '(%(%s)T - %(%s)T) / 60' "$crontab_line" now)))
echo "Next run in $((delta/60)) hours and $((delta%60)) minutes."