Sleep till next 15 minute hourly interval (00:00, 00:15, 00:30, 00:45)

Viewed 4068

I need my script to sleep till the next 15 minute hourly interval, e.g. on the hour, quarter past, half past, and quarter too.

It will look something like this

While True:
    //do something
    sleepy_time = //calculate time to next interval
    time.sleep(sleepy_time)

You could write a series of if statements to check what the current minutes past the hour is then do ‘if current < 15’ and ‘if current < 30’ etc but that seems messy and inefficient.

EDIT: Building on @martineau's answer this is the code I went with.

import datetime, time

shouldRun = True
if datetime.datetime.now().minute not in {0, 15, 30, 45}:
    shouldRun = False
# Synchronize with the next quarter hour.
while True:
    if shouldRun == False:
        current_time = datetime.datetime.now()
        seconds = 60 - current_time.second
        minutes = current_time.minute + 1
        snooze = ((15 - minutes%15) * 60) + seconds
        print('minutes:', minutes, 'seconds', seconds, ' sleep({}):'.format(snooze))
        localtime = time.asctime( time.localtime(time.time()))
        print("sleeping at " + localtime)
        time.sleep(snooze)  # Sleep until next quarter hour.
        shouldRun = True
    else:
        localtime = time.asctime( time.localtime(time.time()))
        print("STUFF HAPPENS AT " + localtime)
        shouldRun = False

The difference between his answer and this is that this run the else block only once per interval then if the minute is still on the 0, 15, 30, 45 interval calculates the extra seconds to add to the minutes to sleep till the next interval.

4 Answers

You can achieve this using datetime...

A call to datetime.datetime.now() will return a datetime which you can get the current minute past the hour with .minute.

Once we have the number of minutes past the hour, we can do that modulo 15 to get the number of minutes to the next interval of 15.

From here, simply do a call to time.sleep() with that number of minutes times 60 (60 seconds in a minute).

The code for this may look something like:

import datetime, time

minutesToSleep = 15 - datetime.datetime.now().minute % 15
time.sleep(minutesToSleep * 60)
print("time is currently at an interval of 15!")

time.sleep(15*60 - time.time() % (15*60))

15*60 is a numer of seconds in every 15 mins.

time.time() % (15*60) would be the number of seconds passed in the current 15 min frame (since time 0 is 00:00 by definition). It grows from 0 at XX:00, XX:15, XX:30, XX:45, and up to 15*60-1 (actually, 15*60-0.(0)1 — depends on the precision of time measurements), and then starts to grow from 0 again.

15*60 - time.time() % (15*60) is the number of seconds left till the end of the 15-min frame. It, with a basic math, decreases from 15*60 to 0.

So, you need to sleep that many seconds.

However, keep in mind that sleep will not be very precise. It takes some time to process the internal instructions between time.time() is measured, and time.sleep() is actually called on the system level. Nano-fractions of a second, probably. But in most cases it is acceptable.

Also, keep in mind that time.sleep() does not always sleeps for how long it was asked to sleep. It can be waked up by signals sent to the process (e.g., SIGALRM, SIGUSR1, SIGUSR2, etc). So, besides sleeping, also check that the right time has been reached after time.sleep(), and sleep again if it was not.

import time

L = 15*60

while True:
    #do something

    #get current timestamp as an integer and round to the
    #nearest larger or equal multiple of 15*60 seconds, i.e., 15 minutes
    d = int(time.time())

    m = d%L        
    sleepy_time = 0 if m == 0 else (L - m)

    print(sleepy_time)
    time.sleep(sleepy_time)

I don't think @Joe Iddon's answer is quite right, although it's close. Try this (note I commented-out lines I didn't want running and added a for loop to test all possible values of minute):

import datetime, time

# Synchronize with the next quarter hour.
#minutes = datetime.datetime.now().minute
for minutes in range(0, 59):
    if minutes not in {0, 15, 30, 45}:
        snooze = 15 - minutes%15
        print('minutes:', minutes, ' sleep({}):'.format(snooze * 60))
        #time.sleep(snooze)  # Sleep until next quarter hour.
    else:
        print('minutes:', minutes, ' no sleep')
Related