Carlo
Carlo

Reputation: 1576

Python - running a program every 10 seconds, datetime.now() changes behavior

I was testing a program to do something every N seconds, but I bumped into a weird problem.

If I use something simple like this:

import time

def main():
    start_t = time.time()

    while(True):
        if (time.time()-start_t)%10 == 0:
            print("Test")

if __name__ == "__main__":
    main()

the program works as expected, i.e. it prints "Test" every 10 seconds.

However, I made a small modification, because I need to check at every iteration the current date...if I change the program to this:

import time
from datetime import datetime


def main():
    start_t = time.time()
    path_screenshots = "screenshots"

    while(True):
        path_screenshots_today = f"{path_screenshots}/{datetime.now().strftime('%Y_%m_%d')}/"
        if (time.time()-start_t)%10 == 0:
            print(f"Checking folder {path_screenshots_today}...")

if __name__ == "__main__":
    main()

I would expect the program to print "Checking folder {path_screenshots_today}" every 10 seconds again, but instead it keeps running, without printing anything. I understand that the result of the operation (time.time()-start_t)%10 is never precisely equal to 0, which might be creating the issue...but then, why does it even work in the first case?

Upvotes: 1

Views: 881

Answers (3)

BlackBear
BlackBear

Reputation: 22989

The first case works because the time is checked frequently enough, which does not happen in the second case because of the delay introduced by the string formatting. A more robust way is the following:

start_t = time.time()
while True:
    path_screenshots_today = f"{path_screenshots}/{datetime.now().strftime('%Y_%m_%d')}/"
    tt = time.time()
    if tt - start_t >= 10:
        print(f"Checking folder {path_screenshots_today}...")
        start_t = tt  # set last check time to "now"

And an even better way would be:

while True:
    path_screenshots_today = f"{path_screenshots}/{datetime.now().strftime('%Y_%m_%d')}/"
    print(f"Checking folder {path_screenshots_today}...")
    time.sleep(10)

This avoids "busy waiting", i.e. keeping the CPU running like crazy.

Upvotes: 1

Ken Kinder
Ken Kinder

Reputation: 13150

It's a coincidence of how often the check is happening. If you actually loop over and print your value, you'll notice it's floating point:

    while(True):
        print('Current value is, ', (time.time()-start_t)%10)

You'll see output like this:

Current value is,  0.45271849632263184
Current value is,  0.45272231101989746

Given that you're doing so little in your loop, the odds are good that you'll coincidentally do that evaluation when the current value is exactly 0.0. But when you add some extra computation, even just the string formatting in datetime, each iteration of your loop will take a little longer and you might just happily skip over 0.0.

So strictly speaking, you should cast your value to an int before comparing it to 0. Eg, int((time.time() - start_t) % 10) == 0. That will be true for an entire second, until the modulus value is once again not zero, a second after it's first true.

A better solution, however, is to probably just use the time.sleep() function. You can call time.sleep to sleep for a number of seconds:

time.sleep(10)   # Sleep for 10 seconds

Upvotes: 1

LeopardShark
LeopardShark

Reputation: 4446

I suspect it is working in the first case because the loop is running fast enough that it happens to line up. The lag created by creating path_screenshots_today (particularly the datetime.now() call) causes it not to line up as often. To actually do what you want, try:

import time
from datetime import datetime


def main():
    last = time.time()
    path_screenshots = "screenshots"

    while True:
        path_screenshots_today = f"{path_screenshots}/{datetime.now().strftime('%Y_%m_%d')}/"
        if time.time() - last >= 10:
            last = time.time()
            print(f"Checking folder {path_screenshots_today}...")

if __name__ == "__main__":
    main()

Upvotes: 2

Related Questions