10

This is a bit difficult to explain, so I apologize if this doesn't make much sense.

I have a program where I am doing some scheduling. One of the settings it has is to run a task weekly on certain days. For example, weekly on Monday, Wednesday and Friday.

Consider the example where the current task is scheduled for 1/2/2012, which is a Monday, I already have a bunch of code working to the point where I know the next task run should be on the wednesday following 1/2/2012. All I need to do is calculate the actual date of that Wednesday (1/4/2012).

I actually have the day of the week as the corresponding integer from date.weekday(), so in this case I have 2 which represents wednesday.

Whats the best way to handle something like this? I feel like there should be a fairly simple solution, but it isn't coming to mind. I was thinking of using a calendar object to search through to find the day of the week I want, but that seems like overkill.

Jon
  • 3,212
  • 32
  • 35

4 Answers4

14

Use dateutil.relativedelta:

from dateutil import relativedelta
import datetime

today = datetime.date.today()
# datetime.date(2012, 1, 3)

today + relativedelta.relativedelta(weekday=2) # 2 is Wednesday
# datetime.date(2012, 1, 4)

today + relativedelta.relativedelta(weekday=6) # 6 is Sunday
# datetime.date(2012, 1, 8)

today + relativedelta.relativedelta(weekday=1) # 1 is Tuesday
# datetime.date(2012, 1, 3)
# returns today

today + relativedelta.relativedelta(weeks=1, weekday=1)
# datetime.date(2012, 1, 10)
# returns Tuesday at least one week ahead
eumiro
  • 207,213
  • 34
  • 299
  • 261
8

Use a timedelta to add to a date. For example, using some date d as the scheduled date for a current task, and some day next_day (the next day you'd like to run the task).

from datetime import date, timedelta
...
n = (next_day - d.weekday()) % 7 # mod-7 ensures we don't go backward in time
next_run_date = d + timedelta(days=n)
aganders3
  • 5,838
  • 26
  • 30
  • This didn't seem to work for me. It was off by several days when I ran my unit test with the change. I think what might throw things off is that in Python, Monday is 0 and Sunday is 6. I think Monday being 0 throws this off, but I am not sure. – Jon Jan 03 '12 at 05:17
  • 2
    I think you want `next_day - d.weekday()` instead. – Mark Ransom Jan 03 '12 at 05:22
  • Thanks @MarkRansom, I think you're right and I fixed my answer. @Jon, can you try it again? I don't think having Monday=0 should be a problem so long as `next_day` uses the same convention. – aganders3 Jan 03 '12 at 05:34
  • That does work now, thanks for the help. I was originally trying something very similar, but it just wasn't quite right. All of my unit tests are passing now. – Jon Jan 03 '12 at 12:18
0

We know that:

  • from Monday to Wednesday there is 2 days of difference.
  • from Wednesday to Friday there is 2 days of difference.
  • from Friday to Monday there is 3 days of difference.

So, this is as simple as adding the days of difference between scheduled tasks:

from datetime import datetime, timedelta
first_scheduled_task = datetime(year=2012, month=1, day=2)
second_scheduled_task = first_scheduled_task + timedelta(2)
third_scheduled_task = second_scheduled_task + timedelta(2)
fourth_scheduled_task = third_scheduled_task + timedelta(3)

This would give us as result:

>>> first_scheduled_task
datetime.datetime(2012, 1, 2, 0, 0) # Monday 1/2/2012
>>> second_scheduled_task
datetime.datetime(2012, 1, 4, 0, 0) # Wednesday 1/4/2012
>>> third_scheduled_task
datetime.datetime(2012, 1, 6, 0, 0) # Friday 1/6/2012
>>> fourth_scheduled_task
datetime.datetime(2012, 1, 9, 0, 0) # Monday 1/9/2012
juliomalegria
  • 24,229
  • 14
  • 73
  • 89
  • I should clarify I was using Monday and Wednesday as a generic example. The repeat could be any combination of days. For example, Monday, Thursday, Saturday. So this won't work. – Jon Jan 03 '12 at 05:11
0

Use dateutil for working with scheduling and recurrences.

warvariuc
  • 57,116
  • 41
  • 173
  • 227