Skip to content

Instantly share code, notes, and snippets.

@vladimirgoncharov
Created September 20, 2022 15:33
Show Gist options
  • Save vladimirgoncharov/c313bfe9b068e0007318af3de38d1bc0 to your computer and use it in GitHub Desktop.
Save vladimirgoncharov/c313bfe9b068e0007318af3de38d1bc0 to your computer and use it in GitHub Desktop.
Calculate time of crons
from __future__ import print_function
import sys
# import debugpy
from dateutil import rrule
from datetime import datetime, timezone, timedelta
from croniter import croniter
from collections import defaultdict
def main(crontab, start, end, fromDuration):
"""
Take entries in a crontab file, find slots where no jobs are scheduled to
run.
1. Install dependencies:
- Python 3
- Python package manager https://pip.pypa.io/en/stable/installing/
2. Install additional modules:
- pip3 install python-dateutil
- pip3 install croniter
3. How to run:
python cron_slots.py <crontabfile> <start time dd/mm/yyyy h24:mi> <end time dd/mm/yyyy h24:mi> <from duration in minutes>
crontab -l > crontab_01012016
python cron_slots.py "path/to/crontab_01012016" "19/08/2022 00:00" "02/09/2022 23:59" "1"
Parameters
----------
crontab: A file with output of crontab -l command.
start: start of time period, datetime.
end: end of time period, datetime.
fromDuration: find of time period from the duration in minutes.
returns
-------
None, output is printed out to standard out in below format
04/02/2016 00:00 - Free 1 min
04/02/2016 00:01 - Busy with /cfes/bin/script1.sh # Note this is the first script running at 00:01
04/02/2016 00:01 - Busy with /cfes/bin/script2.sh # Note this is the second script running at 00:01
04/02/2016 00:10 - Free 9 min
04/02/2016 00:11 - Busy with /cfes/bin/script3.sh # Note this is the thirst script running at 00:01
"""
cron_times = defaultdict(list)
f = open(crontab, 'rt')
print('IGNORED LIST START -------------------')
for line in f:
try:
line_split = line.split()
# take the cron time part, e.g 10 * * * *
cron_entry = ' '.join(line_split[:5])
cron_times_iter = croniter(cron_entry, start)
except Exception as _:
if line != '\n':
print(line)
continue
for epoch in cron_times_iter:
dt = datetime.fromtimestamp(epoch, timezone.utc)
if dt > end:
break
cron_task = ' '.join(line_split[5:])
cron_times[dt.strftime('%d%m%Y%H%M')].append(cron_task)
print('IGNORED LIST END -------------------')
print('FREE TIME START -------------------')
duration = 0
lastCronDate = None
dates = rrule.rrule(rrule.MINUTELY, dtstart=start, until=end)
for dt in dates:
if dt.strftime('%d%m%Y%H%M') in cron_times:
isPrintable = duration > fromDuration
if isPrintable and lastCronDate is not None:
print('-------------------')
for task in cron_times.get(lastCronDate.strftime('%d%m%Y%H%M'), {}):
print(lastCronDate.strftime('%d/%m/%Y %H:%M'), '- Busy with ',
task)
if isPrintable:
print((dt - timedelta(minutes=1)).strftime('%d/%m/%Y %H:%M'), '- Free ',
duration, 'min')
print('-------------------')
duration = 0
lastCronDate = dt
else:
duration += 1
isPrintable = duration > fromDuration
if isPrintable and lastCronDate is not None:
print('-------------------')
for task in cron_times.get(lastCronDate.strftime('%d%m%Y%H%M'), {}):
print(lastCronDate.strftime('%d/%m/%Y %H:%M'), '- Busy with ',
task)
if isPrintable:
print(end.strftime('%d/%m/%Y %H:%M'), '- Free ',
duration, 'min')
print('FREE TIME END -------------------')
if __name__ == '__main__':
# debugpy.listen(5678)
# print("Waiting for debugger attach")
# debugpy.wait_for_client()
# debugpy.breakpoint()
cronfile = sys.argv[1]
start = datetime.strptime(sys.argv[2], '%d/%m/%Y %H:%M').replace(tzinfo=timezone.utc)
end = datetime.strptime(sys.argv[3], '%d/%m/%Y %H:%M').replace(tzinfo=timezone.utc)
fromDuration = int(sys.argv[4])
main(cronfile, start, end, fromDuration)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment