Reputation: 11
I'm new to learning python, for the past 2 days I've been looking for an answer to this. I want to add code that can make it so it pauses the script (not ending it) and then at an exact time it will run the few lines below it. Such as if I wanted it to pause it until 10:40 pm, I need it to be accurate to the very millisecond. Example: 2021 2 21 22 40 00 00 Year month day hour minute(s) second(s) millisecond(s)
The closest code to it that I got didn't do it accurately and most of the time had a second or more delay.
t = time_module.strptime('2021-02-21 22:25:14', '%Y-%m-%d %H:%M:%S')
t = time_module.mktime(t)
scheduler_e = scheduler.enterabs(t, 1, myfunc, ())
scheduler.run()
Upvotes: 1
Views: 52
Reputation: 469
You can use the time module to do this:
import time
def call_at_time(fun, t):
sleep_time = t - time.time()
assert sleep_time > 0 # make sure t is in the future
time.sleep(sleep_time)
fun()
Using this function looks like this:
t = time.strptime("2021-02-22 23:50:30", "%Y-%m-%d %H:%M:%S")
t = time.mktime(t)
print(f"scheduled at {t}")
call_at_time(lambda: print(f"hello at {time.time()}"), t)
So how accurate is this? Here is a tiny experiment to find out. Please use a larger n
if you want more reliable results.
n = 20
results = []
for _ in range(n):
t = time.time() + 2 # 2 seconds in the future
call_at_time(lambda: results.append(abs(time.time() - t)), t)
print(f"min={min(results):5.4f}, max={max(results):5.4f}, mean={sum(results) / n:5.4f}")
On my Windows box this gives me:
min=0.0010, max=0.0200, mean=0.0094
So on average we are about 9ms off, but sometimes we are as much as 20ms off. This inaccuracy comes from two sources
To illustrate the (in-)accuracy of time.time(), you can just run it in a loop and print the resulting numbers.
while True:
print(time.time())
On my Windows machine, this gives me something like this:
...
1614072496.454525
1614072496.454525
1614072496.454525
1614072496.4555244
1614072496.4555244
1614072496.4595287
1614072496.4595287
1614072496.4595287
1614072496.4595287
1614072496.4595287
1614072496.4595287
1614072496.4595287
1614072496.4605293
1614072496.4605293
1614072496.4605293
...
As you can see, time.time() can be pretty erratic, and that of course limits how accurately you can achieve the desired task (and how accurate my experimental results above actually are...).
If you are on a system where time.time() gives you better accuracy or you find another means of getting better system time, you might get better results by combining sleep with a bit of busy waiting. That way you can at least eliminate the inaccuracy you get from time.sleep().
def call_at_time_high_precision(fun, t, busy_waiting_time=1):
sleep_time = t - time.time()
assert sleep_time > 0 # make sure time is in the future
if sleep_time > busy_waiting_time:
time.sleep(sleep_time - busy_waiting_time)
while t > time.time(): # busy wait until the event
pass
fun()
Upvotes: 1