Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to calculate next Friday at 3am?

How can you calculate the following Friday at 3am as a datetime object?

Clarification: i.e., the calculated date should always be greater than 7 days away, and less than or equal to 14.

like image 822
mpen Avatar asked Mar 13 '10 01:03

mpen


3 Answers

If you install dateutil, then you could do something like this:

import datetime
import dateutil.relativedelta as reldate

def following_friday(dt):   
    rd=reldate.relativedelta(
        weekday=reldate.FR(+2),
        hours=+21)
    rd2=reldate.relativedelta(
        hour=3,minute=0,second=0,microsecond=0)
    return dt+rd+rd2

Above, hours=+21 tells relativedelta to increment the dt by 21 hours before finding the next Friday. So, if dt is March 12, 2010 at 2am, adding 21 hours makes it 11pm of the same day, but if dt is after 3am, then adding 21 hours pushs dt into Saturday.

Here is some test code.

if __name__=='__main__':
    today=datetime.datetime.now()
    for dt in [today+datetime.timedelta(days=i) for i in range(-7,8)]:
        print('%s --> %s'%(dt,following_friday(dt)))

which yields:

2010-03-05 20:42:09.246124 --> 2010-03-19 03:00:00
2010-03-06 20:42:09.246124 --> 2010-03-19 03:00:00
2010-03-07 20:42:09.246124 --> 2010-03-19 03:00:00
2010-03-08 20:42:09.246124 --> 2010-03-19 03:00:00
2010-03-09 20:42:09.246124 --> 2010-03-19 03:00:00
2010-03-10 20:42:09.246124 --> 2010-03-19 03:00:00
2010-03-11 20:42:09.246124 --> 2010-03-19 03:00:00
2010-03-12 20:42:09.246124 --> 2010-03-26 03:00:00 
2010-03-13 20:42:09.246124 --> 2010-03-26 03:00:00
2010-03-14 20:42:09.246124 --> 2010-03-26 03:00:00
2010-03-15 20:42:09.246124 --> 2010-03-26 03:00:00
2010-03-16 20:42:09.246124 --> 2010-03-26 03:00:00
2010-03-17 20:42:09.246124 --> 2010-03-26 03:00:00
2010-03-18 20:42:09.246124 --> 2010-03-26 03:00:00
2010-03-19 20:42:09.246124 --> 2010-04-02 03:00:00

while before 3am:

two = datetime.datetime(2010, 3, 12, 2, 0)
for date in [two+datetime.timedelta(days=i) for i in range(-7,8)]:
    result = following_friday(date)
    print('{0}-->{1}'.format(date,result))

yields:

2010-03-05 02:00:00-->2010-03-12 03:00:00
2010-03-06 02:00:00-->2010-03-19 03:00:00
2010-03-07 02:00:00-->2010-03-19 03:00:00
2010-03-08 02:00:00-->2010-03-19 03:00:00
2010-03-09 02:00:00-->2010-03-19 03:00:00
2010-03-10 02:00:00-->2010-03-19 03:00:00
2010-03-11 02:00:00-->2010-03-19 03:00:00
2010-03-12 02:00:00-->2010-03-19 03:00:00
2010-03-13 02:00:00-->2010-03-26 03:00:00
2010-03-14 02:00:00-->2010-03-26 03:00:00
2010-03-15 02:00:00-->2010-03-26 03:00:00
2010-03-16 02:00:00-->2010-03-26 03:00:00
2010-03-17 02:00:00-->2010-03-26 03:00:00
2010-03-18 02:00:00-->2010-03-26 03:00:00
2010-03-19 02:00:00-->2010-03-26 03:00:00
like image 156
unutbu Avatar answered Oct 01 '22 19:10

unutbu


Here's a function and a test that it meets the OP's requirements:

import datetime

_3AM = datetime.time(hour=3)
_FRI = 4 # Monday=0 for weekday()

def next_friday_3am(now):
    now += datetime.timedelta(days=7)
    if now.time() < _3AM:
        now = now.combine(now.date(),_3AM)
    else:
        now = now.combine(now.date(),_3AM) + datetime.timedelta(days=1)
    return now + datetime.timedelta((_FRI - now.weekday()) % 7)

if __name__ == '__main__':
    start = datetime.datetime.now()
    for i in xrange(7*24*60*60):
        now = start + datetime.timedelta(seconds=i)
        then = next_friday_3am(now)
        assert datetime.timedelta(days=7) < then - now <= datetime.timedelta(days=14)
        assert then.weekday() == _FRI
        assert then.time() == _3AM
like image 25
Mark Tolonen Avatar answered Oct 01 '22 19:10

Mark Tolonen


I like dateutil for such tasks in general, but I don't understand the heuristics you want -- as I use the words, if I say "next Friday" and it's Thursday I would mean tomorrow (probably I've been working too hard and lost track of what day of the week it is). If you can specify your heuristics rigorously they can surely be programmed, of course, but if they're weird and quirky enough you're unlikely to find them already pre-programmed for you in existing packages;-).

like image 39
Alex Martelli Avatar answered Oct 01 '22 17:10

Alex Martelli