Reputation: 25
I would like a timer (Using Python 3.8 currently) that first checks the system time or Naval Observatory clock, so it can be started at any time and synch with the 00 seconds.
I'm only interested in the number of seconds on the system clock or Naval Observatory. At the top of every minute, i.e when the seconds = 00 I need to write data to a DataFrame or database, then sleep again for another 60 seconds.
I first checked the system time, determined how long it is from the 00 seconds, and placed the first delay for that amount. After that it should delay or sleep for 60 seconds, then run again. Data is constantly changing but at this point I only need to write the data every 60 seconds, would like to also have it have the capability of using other time frames like 5 minutes, 15 minutes etc, but once the first is done the other time frames will be easy.
Here is my lame attempt, it runs a few iterations then quits, and I'm sure it's not very efficient
def time_delay():
sec = int(time.strftime('%S'))
if sec != 0:
wait_time = 60 - sec
time.sleep(wait_time)
sec = int(time.strftime('%S'))
wait_time = 60 - sec
elif time.sleep(60):
time_delay()
Upvotes: 1
Views: 312
Reputation: 123453
This isn't quite as general as you wanted, and as I said in a comment, it's not possible to synchronize exactly with the time source due to the inherent overhead involved (but you can get pretty close).
What the following does is define a Thread
subclass that can be used to call a user specified function at fixed intervals starting at a whole multiple of seconds on the system clock.
It does this by first delaying until the next multiple
of the specified number of seconds will occur, and then from that point on calling the function every interval
number of seconds while compensating for however long the call to the specified function took to execute.
from threading import Thread, Event
import time
class TimedCalls(Thread):
def __init__(self, func, interval, multiple):
super().__init__()
self.func = func
self.interval = interval
if multiple == 0:
self.multiple = 60 # Avoid ZeroDivisionError.
else:
self.multiple = multiple
self.stopped = Event()
def cancel(self):
self.stopped.set()
def start(self):
# Initially sync to a whole multiple of the interval.
frac = self.multiple - (time.time() % self.multiple)
time.sleep(frac)
super().start()
def run(self):
next_call = time.time()
while not self.stopped.is_set():
self.func(next_call) # Target activity.
next_call = next_call + self.interval
# Block until beginning of next interval (unless canceled).
self.stopped.wait(next_call - time.time())
def my_function(tm):
print(f"{tm} → {time.strftime('%H:%M:%S', time.localtime(tm))}")
# Call function every 10 sec starting at multiple of 5 secs
timed_calls = TimedCalls(my_function, 10, 5)
timed_calls.start()
try:
time.sleep(125) # Let the timed calls occur.
finally:
timed_calls.cancel()
print('done')
Sample output:
1617662925.0018559 → 15:48:45
1617662935.0018559 → 15:48:55
1617662945.0018559 → 15:49:05
1617662955.0018559 → 15:49:15
1617662965.0018559 → 15:49:25
1617662975.0018559 → 15:49:35
1617662985.0018559 → 15:49:45
1617662995.0018559 → 15:49:55
1617663005.0018559 → 15:50:05
1617663015.0018559 → 15:50:15
1617663025.0018559 → 15:50:25
1617663035.0018559 → 15:50:35
1617663045.0018559 → 15:50:45
done
Upvotes: 1
Reputation: 54698
This will call a function when the seconds are 0:
def time_loop(job):
while True:
if int(time.time()) % 60 == 0:
job()
time.sleep( 1 )
Upvotes: 1