Welcome, guest | Sign In | My Account | Store | Cart

What is the 2nd last Friday in May 2005 ? What is the first Monday in August 2006 ?

cutoff_date = dow_date_finder(SECONDLAST,FRI,OCT,2005)

Python, 50 lines
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
import datetime   # a thing of beauty and a joy forever

FIRST = 0
SECOND = 1
THIRD = 2
FOURTH = FORTH = 3  # for people who have finger trouble
FIFTH = 4
LAST = -1
SECONDLAST = -2
THIRDLAST = -3

MONDAY = MON = 0
TUESDAY = TUE = TUES = 1
WEDNESDAY = WED = 2
THURSDAY = THU = THUR = 3
FRIDAY = FRI = 4
SATURDAY = SAT = 5
SUNDAY = SUN = 6

JANUARY = JAN = 1
FEBRUARY = FEB = 2
MARCH = MAR = 3
APRIL = APR = 4
MAY = 5
JUNE = JUN = 6
JULY = JUL = 7
AUGUST = AUG = 8
SEPTEMBER = SEP = 9
OCTOBER = OCT = 10
NOVEMBER = NOV = 11
DECEMBER = DEC = 12

def dow_date_finder(which_weekday_in_month=FIRST,day=MONDAY,month=JANUARY,year=2000):
    dt = datetime.date(year,month,1)
    dow_lst = []
    while dt.weekday() != day:
        dt = dt + datetime.timedelta(days=1)
    while dt.month == month:
        dow_lst.append(dt)
        dt = dt + datetime.timedelta(days=7)
    return dow_lst[which_weekday_in_month]  # may raise an exception if slicing is wrong


if __name__ == "__main__":
    print "2nd tuesday of may 2005"
    print dow_date_finder(SECOND,TUESDAY,MAY,2005)
    print "last wednesday of april 2005"
    print dow_date_finder(LAST,WEDNESDAY,APRIL,2005)
    print "secondlast friday of october 2005 - short form"
    print dow_date_finder(SECONDLAST,FRI,OCT,2005)

Commercial programs often need to know these days : usually they are special because they're holidays or financial periods or whatever.

I personally don't like the Monday=0 that we find in Python - it goes against "cron" standard, so I always battle a but with it. So "hash-defining" it as above makes it slightly more palatable.

The function should really be hardened a lot more : checking for invalid days of week, days of month and the "which value". But it runs in a consistent environment so I haven't felt the need for that.

3 comments

Raymond Hettinger 18 years, 9 months ago  # | flag

Alternate version using the calendar module.

from calendar import monthrange

def dow_date_finder(which_weekday_in_month=FIRST,day=MONDAY,month=JANUARY,year=2000):
    bom, days = monthrange(year, month)
    firstmatch = (day - bom) % 7 + 1
    return xrange(firstmatch, days+1, 7)[which_weekday_in_month]
Chris Smith 18 years ago  # | flag

You might want to embed that last line in a try/except to catch the case when the requested day does not exist, e.g. there's not a 5th Thursday of Nov 1977 but there is in 1978:

try:
    return xrange(firstmatch, days+1, 7)[which_weekday_in_month]
except:
    return None
greg p 16 years, 8 months ago  # | flag

I put this into an online utility here:

http://www.utilitymill.com/utility/Nth_Weekday_in_Month

Hopefully it will be useful to people. Feel free to improve it, some of the parameters still aren't working.

Created by Mark Pettit on Mon, 13 Jun 2005 (PSF)
Python recipes (4591)
Mark Pettit's recipes (1)

Required Modules

Other Information and Tasks