How to schedule a periodic task that is immune to system time change using Python
Question: I am using python's sched module to run a task periodically, and I think I
have come across a bug.

I find that it relies on the time of the system on which the python script is
run. For example, let's say that I want to run a task every 5 seconds. If I
forward the system time, the scheduled task will run as expected. However, if
I rewind the system time to, say 1 day, then the next scheduled task will run
in 5 seconds + 1 day.

If you run the script below and then change your system time by a few days
back, then you can reproduce the issue. The problem can be reproduced on Linux
and Windows.

    
    
    import sched
    import time
    import threading
    
    period = 5
    scheduler = sched.scheduler(time.time, time.sleep)
    
    def check_scheduler():
        print time.time()
        scheduler.enter(period, 1, check_scheduler, ())
    
    if __name__ == '__main__':
        print time.time()
    
        scheduler.enter(period, 1, check_scheduler, ())
    
        thread = threading.Thread(target=scheduler.run)
        thread.start()
        thread.join()
        exit(0)
    

Anyone has any python solution around this problem?


Answer: From [the sched
documentation](https://docs.python.org/2/library/sched.html#module-sched):

> class sched.scheduler(timefunc, delayfunc)
>
> The scheduler class defines a generic interface to scheduling events. It
> needs two functions to actually deal with the “outside world” — timefunc
> should be callable without arguments, and return a number (the “time”, in
> any units whatsoever). The delayfunc function should be callable with one
> argument, compatible with the output of timefunc, and should delay that many
> time units. delayfunc will also be called with the argument 0 after each
> event is run to allow other threads an opportunity to run in multi-threaded
> applications.

The problem you have is that your code uses `time.time()` as `timefunc`, whose
return value (when called without arguments) is the current system time and is
thus affected by re-winding the system clock.

To make your code immune to system time changes you'd need to provide a
`timefunc` which doesn't depend on the system time, start/current timestamps,
etc.

You can write your own function, for example one returning the number of
seconds since your process is started, which you'd have to **actually count**
in your code (i.e. don't `compute it` based on timestamp deltas). The
`time.clock()` function _might_ help, if it's based on CPU time counters, but
I'm not sure if that's true or not.

