Search code examples
pythonschedule

How do I make a function start working at a certain time and at a certain interval?


I'm trying to make the function print1 start the function print2 (which will run every 30 min) But I can't stop this process at a certain time. The function keeps running. I need my function (e.g. print1) to run every day at 6 am. And make calculations at intervals of 30 minutes. And end at 10 pm. And the next day all over again.

import schedule
from schedule import every, repeat, run_pending


def print2():
    print(" interval 30 sec")
    # return schedule.CancelJob


def print1():
    schedule.every(30).minutes.do(print2)
    print("run")
    return schedule.CancelJob


schedule.every().day.at('6:00').do(print1)
job = schedule.every().day.at('10:00').do(print1)
schedule.cancel_job(job)

while True:
    schedule.run_pending()
    time.sleep(1)

Solution

  • The code below creates a job to run every day at 6:00 which creates a repeating job then stops at 10:00. The primary 6:00 job will run every day. To work, need to add a loop to main and call schedule.run_pending().

    Example #1

    from datetime import datetime, timedelta
    import schedule
    import time
    
    class Job:
    
        def __init__(self):
            self.running = False
            self.job = None
    
        def print2(self):
            if debug:
                print(">> interval 1 sec")
            else:
                print(">> interval 30 mins")
    
        def print1(self):
            print("started")
            self.running = True
            if debug:
                self.job = schedule.every(1).seconds.do(self.print2)
                stop = (datetime.now() + timedelta(seconds=30)).strftime("%H:%M:%S")
                print("Stop at:", stop)
                schedule.every().day.at(stop).do(self.cancel)
            else:
                self.job = schedule.every(30).minutes.do(self.print2)
                schedule.every().day.at('10:00').do(self.cancel)
    
        def cancel(self):
            print("cancel job")
            schedule.cancel_job(self.job)
            print("Stopped at ", datetime.now().strftime("%H:%M:%S"))
            self.running = False
            return schedule.CancelJob
    
    # main
    
    # debug = True runs 10 seconds from now then stops repeating job after 30 seconds
    # set debug = False to run at 6:00 and stop at 10:00
    debug = True
    
    job = Job()
    
    if debug:
        now = datetime.now()
        start = now + timedelta(seconds=10)
        start = start.strftime("%H:%M:%S")
        print("current:", now.strftime("%H:%M:%S"))
        print("start:  ", start)
        schedule.every().day.at(start).do(job.print1)
    else:
        schedule.every().day.at('6:00').do(job.print1)
    
    while True:
        if not job.running:
            print("waiting")
        schedule.run_pending()
        time.sleep(1)
    

    Output:

    current: 10:29:38
    start:   10:29:48
    waiting
    waiting ... printed 10x
    started
    Stop at: 10:30:18
    >> interval 1 sec
    >> interval 1 sec ... print 30x
    cancel job
    >> interval 1 sec
    Stopped at  10:30:18
    waiting
    waiting
    ...
    

    Instead of using schedule to start and stop jobs, another approach schedules a single job to run every day. When the scheduled job is activated, it kicks off a new Thread that executes a function at set interval then stops running at a particular time.

    Example #2

    from datetime import datetime, timedelta
    import schedule
    import time
    from threading import Thread
    
    class Job:
    
        def __init__(self):
            self.running = False
    
        def print2(self):
            if debug:
                print(">> interval 1 sec")
            else:
                print(">> interval 30 mins")
            # do something
    
        def check_job(self):
            now = datetime.now()
            if debug:
                stop = now + timedelta(seconds=10)
                sleep_time = 1  # every 1 second
            else:
                # stop at 10am
                stop = now.replace(hour=10, minute=0, second=0)
                sleep_time = 600  # every 10 minutes
            print("Stop at:", stop.strftime("%H:%M:%S"))
            while True:
                # perform the periodic function to do something
                self.print2()
                time.sleep(sleep_time)
                if datetime.now() >= stop:
                    print("Stopped at ", datetime.now().strftime("%H:%M:%S"))
                    self.running = False
                    break
    
        def print1(self):
            print("started")
            self.running = True
            # create and start a new Thread that runs check_job() function
            t = Thread(target=self.check_job, daemon=True)
            t.start()
    
    # uses same main as example #1 above