views:

55

answers:

2

I have three lists that define when a task should be executed:

  1. minute: A list of integers from 0-59 that represent the minutes of an hour of when execution should occur;
  2. hour: A list of integers from 0-23 that represent the hours of a day of when execution should occur
  3. day_of_week: A list of integers from 0-6, where Sunday = 0 and Saturday = 6, that represent the days of a week that execution should occur.

Is there a easy way to calculate what's the timedelta until the next execution in Python?

Thanks!

EDIT: For example, if we have the following lists:

day_of_week = [0]
hour = [1]
minute = [0, 30]

The task should run twice a week at 1:00 and 1:30 every Sunday. I'd like to calculate the timedelta until the next occurance based on current time.

+1  A: 

Using dateutil (edited to address the OP's updated question):

import datetime
import random
import dateutil.relativedelta as dr
import itertools

day_of_week = [1,3,5,6]
hour = [1,10,15,17,20]
minute = [4,34,51,58]

now=datetime.datetime.now()
deltas=[]

for min,hr,dow in itertools.product(minute,hour,day_of_week):
    # dateutil convention: Monday = 0, Sunday = 6.
    next_dt=now+dr.relativedelta(minute=min,hour=hr,weekday=dow)
    delta=next_dt-now
    deltas.append(delta)

deltas.sort()

This is the next timedelta:

print(deltas[0])
# 4 days, 14:22:00

And here is the corresponding datetime:

print(now+deltas[0])
# 2010-09-02 01:04:23.258204

Note that dateutil uses the convention Monday = 0, Sunday = 6.

unutbu
I'm afraid that's not correct. The lists do not need to have the same size. I have added an example to my question. Thanks for the dateutil suggestion, anyway.
jbochi
BTW, using the contants that you generated, the next occurance would be 2010-09-02 01:04:00
jbochi
@jbochi: The data is randomly generated. Every time you run the script the times will be different.
unutbu
Yeah, I know. I meant that if minute=[4, 34, 51, 58], hour=[1, 10, 15, 17, 20] and day_of_week = [1, 3, 5, 6]; the next occurance, considering the current time, would be at 2010-09-02 01:04:00
jbochi
@jbochi: We are probably in different timezones. The result of the script depends on what time your computer thinks `now` is.
unutbu
@unutbu, your new answer is correct, but it's not exactly what I was expecting. If the task was scheduled to run every minute the loop would run 10080 (7*24*60) times. Thanks anyway.
jbochi
@jbochi, why does it matter that it runs 10080 times? It takes a fraction of a microsecond to run, and unless you find a way to add more days to the week scaling won't be an issue.
tgray
A: 

Just in case anybody is interested, this is the code that I developed using ~unutbu suggestions. The main advantage is that it scales fine.

import datetime
import dateutil.relativedelta as dr

def next_ocurrance(minutes, hours, days_of_week):
    # days_of_week convention: Sunday = 0, Saturday = 6
    # dateutil convention: Monday = 0, Sunday = 6

    now = datetime.datetime.now()
    weekday = now.isoweekday()
    execute_this_hour = weekday in days_of_week \
                        and now.hour in hours \
                        and now.minute < max(minutes)

    if execute_this_hour:
        next_minute = min([minute for minute in minutes
                           if minute > now.minute])
        return now + dr.relativedelta(minute=next_minute,
                                      second=0,
                                      microsecond=0)
    else:
        next_minute = min(minutes)

    execute_today = weekday in day_of_week \
                    and (now.hour < max(hours) or execute_this_hour)

    if execute_today:
        next_hour = min([hour for hour in hours if hour > now.hour])
        return now + dr.relativedelta(hour=next_hour,
                                      minute=next_minute,
                                      second=0,
                                      microsecond=0)
    else:
        next_hour = min(hours)
        next_day = min([day for day in days_of_week if day > weekday] \
                       or days_of_week)

        return now + dr.relativedelta(weekday=(next_day - 1) % 7,
                                      hour=next_hour,
                                      minute=next_minute,
                                      second=0,
                                      microsecond=0)
if __name__=='__main__':
    day_of_week = [4]
    hour = [1, 10, 12, 13]
    minute = [4, 14, 34, 51, 58]
    print next_ocurrance(minute, hour, day_of_week)
jbochi