python -m pip install schedule
see here at pypi and here at readthedocs. Summary
import schedule
import time
def job():
print("I'm working...")
schedule.every(10).seconds.do(job)
schedule.every(10).minutes.do(job)
schedule.every().hour.do(job)
schedule.every().day.at("10:30").do(job)
schedule.every(5).to(10).minutes.do(job)
schedule.every().monday.do(job)
schedule.every().wednesday.at("13:15").do(job)
schedule.every().minute.at(":17").do(job)
while True:
schedule.run_pending()
time.sleep(1)
aside
I wrote a very simple scheduling helper, named sleepuntil where you'd run sleepuntil 03:45; cmd args....
It doesn't do any of the actual scheduling, rather it computes the number of seconds until the desired time
and sleeps that number of seconds. It is basically sleep but with a calculator to work out the seconds.
It's very rough, since if I'm just writing for me, and the program is small, I don't care for
'software engineering best practices' --- for me, the best way to manage code complexity is not to
have it in the first place: this is around 100 lines all in, and most of that is code for parsing and
printing times. At the time I wrote this, I wasn't aware of how f"{s:<50}", or f"{s^50}" worked,
let alone f"{s:=^{w}}" or x="*";f"{s:{x}^{w}". See AdvancedFormatStrings.
#!/usr/bin/python
import sys, os
from datetime import datetime
from time import sleep
args = sys.argv[1:]
if len(args) < 1 or len(args) > 2:
print("""sleepuntil time
where time has format 12:34""")
exit(1)
def parse_time(x):
a = x.split(":")
if len(a) < 2 or len(a) > 3:
raise ValueError("Time should be in the format hh:mm or hh:mm:ss")
if len(a) == 2:
h,m = map(int,a)
s = 0
else:
h,m,s = map(int,a)
return (h,m,s)
def format_secs(x):
s = x % 60
x //= 60
m = x % 60
x //= 60
if m > 0 or x > 0:
a = f"{s:02d}"
else:
return "{s}"
if x > 0:
a = f"{x}:{m:02d}:{a}"
else:
a = f"{m}:{a}"
return a
def compute_secs_until(x):
h,m,s = parse_time(x)
now = datetime.now()
h1 = now.hour
m1 = now.minute
s1 = now.second
secs = 3600*h+60*m+s
secs1 = 3600*h1+60*m1+s1
dt = secs - secs1
if dt < 0:
dt += 24*3600
return dt
def do_sleep():
try:
secs = compute_secs_until(args[0])
except Exception as e:
print(f"Exception {e}")
exit(1)
if len(args) > 1:
days = int(args[1])
secs += 24*3600*days
d = secs // (24*3600)
h = (secs % (24*3600)) // 3600
m = (secs % 3600) // 60
s = (secs % 60)
hms = []
if d > 0:
hms.append(f"{d} day")
if d != 1:
hms[-1] += "s"
if h > 0:
hms.append(f"{h} hour")
if h != 1:
hms[-1] += "s"
if m > 0:
hms.append(f"{m} minute")
if m != 1:
hms[-1] += "s"
if s > 0:
hms.append(f"{s} second")
if s != 1:
hms[-1] += "s"
if len(hms) == 0:
t = "0 seconds"
elif len(hms) == 1:
t = hms[0]
else:
hms1 = hms[:-1]
hms2 = hms[-1]
t = f"{', '.join(hms1)} and {hms2}"
try:
print(f"Sleeping {secs} seconds == {t}")
for s in range(secs):
cols = os.get_terminal_size().columns
tr = "Time remaining: "
a = f"{format_secs(secs-s)} == {secs-s} seconds"
if len(a) >= cols:
ostr = a
elif len(a) + len(tr) + 1 >= cols:
ostr = a + " " + "="*(cols - len(a) - 1)
else:
ostr = tr + a
ostr = ostr + " " + "="*(cols - len(ostr) - 1)
print(f"\r{ostr}",end="")
sleep(1)
except KeyboardInterrupt:
print("\nKeyboard Interrupt\n")
exit(1)
if __name__ == "__main__":
do_sleep()