Search code examples
pythonpython-3.xdatetimeexecution

Awaiting execution of a function in Python 3 by using datetimenow?


I'm tinkering with datetimenow()and I'm wondering how would you go about sort of "scheduling" an execution of a function when there are 2 dates (now and future dates)?

Basically I want to keep the programming running when the date (and time) is not the same, but when it is, call some function.

What I mean is:

from time import sleep
import time
import datetime
timenow = datetime.datetime.now()

future = datetime.datetime(2018, 8, 19, 15,28)



while timenow != future:
    sleep(1.0)
if timenow == future:
    '''calling some function'''

Result:

Running this code only seems to keep looping although the minutes specified in future equals the minutes of timenow.


Solution

  • You have two separate problems here, and you need to fix both.


    The first problem is that you never update timenow in your loop. Whatever time it was when your program started, that's the value of timenow forever.

    To fix that, you need to update it each time through the loop:

    while timenow != future:
        sleep(1.0)
        timenow = datetime.datetime.now()
    

    The second problem is that if now is, say, 2018-08-19 15:27:59.123456, that isn't equal to 2018-08-19 15:28:00.000000. And a second later, 2018-08-19 15:28:00.131313 also isn't equal to 2018-08-19 15:28:00.000000. There's about a 1 in a million chance that you happen to hit that microsecond exactly when you're only checking once per second.

    To fix that, just use < instead of !=:

    while timenow < future:
        sleep(1.0)
        timenow = datetime.datetime.now()
    

    Now, 2018-08-19 15:27:59.123456 is less than the time you're waiting for—but 2018-08-19 15:28:00.131313 is not. So, you don't miss it.


    While we're at it:

    There's no need for that if statement at all. You're just testing the opposite of the while condition. But the only way you can get here is if the while condition is false, so the opposite condition will always be true, so why bother checking it?

    Also, if the only thing you're using timenow for is in that check, you don't even need to stick it in a variable; just call now() directly.

    So:

    from time import sleep
    import datetime
    
    future = datetime.datetime(2018, 8, 19, 15,28)
    
    while datetime.datetime.now() < future:
        sleep(1.0)
    '''calling some function'''
    

    Meanwhile, there's really no reason to sleep for a second at a time. Why not just sleep once, until future? In some versions of Python, sleep can return early, so you still need a whileloop, but you can still do this:

    from time import sleep
    import datetime
    
    future = datetime.datetime(2018, 8, 19, 15,28)
    
    while datetime.datetime.now() < future:
        sleep((future - datetime.datetime.now()).total_seconds())
    '''calling some function'''
    

    Most of the time, this will sleep exactly once—occasionally maybe two or three times—instead of over and over again, so it won't, say, stop your laptop from going into low-power mode.

    Also, there's a lot less chance that it'll wake up at, say, 2018-08-19 15:28:00.987654 instead of (very close to) on the second. That may not matter for your use, but if it does matter, waking up on the second is surely the one you want.