0

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.

KoyaCho
  • 155
  • 3
  • 12
  • Hi, the `timenow` wouldn't change since you're assigning it as a static variable, and not incrementing it. Here both `future` and `timenow` is fixed, hence they will not change, for it to equal `you need to increment `timenow` by a second. Then only your condition will match, otherwise it's a infinite loop. – user2906838 Aug 19 '18 at 01:20

2 Answers2

3

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.

abarnert
  • 354,177
  • 51
  • 601
  • 671
  • Very comprehensive and detailed. Thank you for the explanation, it helps me a lot. Also if you don't mind, would you happen to know if this (keeping the while loop running) is better than using multithreading? – KoyaCho Aug 19 '18 at 01:57
  • @KoyaCho If you don't have anything else to do at the same time, there's no reason to use a thread. It won't really _hurt_ anything, but it's just making things more complicated for no benefit. – abarnert Aug 19 '18 at 02:03
1

What you will need to do is specify how precise you want that equality to be. To do this you will specify a range of time that is acceptably considered to be "equal". See this SO post on an example of how to do that. You'll end up with something as straight forward as

if min_future_time < timenow and timenow < max_future_time:
  # Do something.
btin
  • 306
  • 2
  • 9