Python: Number of the Week in a Month

The modulo-style approach shown in other answers can be misleading. Imagine weeks in a year. THere are 52 chunks of 7 days in any 365 day year, with one day left over. So if for my first year, the 52nd week ends on Dec 30, and I have Dec 31 left to worry about.

I could either consider that there are 53 weeks in the year, and have the 53rd week be 31 Dec, 1 Jan, 2 Jan, 3 Jan … Or, more conventionally, I consider that the first week of the next year actually begins on Dec 31. This is how your diary pocket book does it.

Of course this means that the next year the 52nd week ends not on Dec 30 now, but Dec 29.
And each year it creeps back one day at a time, until the 6th year where we have moved the end of 52nd week back 6 days (and thrown in a leap day for good measure) so the whole of the 1st week of 2017 would be contained in the year 2016, and that would be silly. So 2016 will have 53 weeks in it.

The exact same logic applies to months, however it can be harder to spot. Unfortunately you choose August 2011 which has a neat arrangement of starting the 1st of the month on a monday.

>>> print calendar.month(2011,8)
    August 2011
Mo Tu We Th Fr Sa Su
 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

>>> print calendar.month(2011,9)
   September 2011
Mo Tu We Th Fr Sa Su
          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

29 of Aug is in 5th week of Aug, but with same logic, the 1st, 2nd 3rd 4th of Sept would also be in the 5th week of Aug, and so cannot be in 1st week of Sept.

So 29 Sept would be, by the simple divide number of days by 7 approach, be in 5th week of September, but looking at calendar above, if 1-4 of sept are in August, then 29 Sept is in 4th week of Sept.

It all depends on your defintion of when a week begins.

import datetime
import calendar

# I am assuming that the first week of a month starts with the first monday of a month...
#I *think* my logic is OK - if Monday (0) is the start of the week, then
#any dayof the month minus its own day of week (0,1,2...) must be positive
#if that day is on or after the first monday of the month

def week_of_month(tgtdate):

    days_this_month = calendar.mdays[tgtdate.month]
    for i in range(1, days_this_month):
        d = datetime.date(tgtdate.year, tgtdate.month, i)
        if d.day - d.weekday() > 0:
            startdate = d
            break
    # now we canuse the modulo 7 appraoch
    return (tgtdate - startdate).days //7 + 1

tgtdates = [datetime.date(2011, 8, 29),
            datetime.date(2011, 8, 1)
            ]

for tgtdate in tgtdates:
    print tgtdate,
    print "is in week %s" % week_of_month(tgtdate)

print calendar.month(tgtdate.year,tgtdate.month)


 # 2011-09-29 is in week 4
 # 2011-09-01 is in week 0
 #    September 2011
 # Mo Tu We Th Fr Sa Su
 #           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

 # 2011-08-29 is in week 5
 # 2011-08-01 is in week 1
 #     August 2011
 # Mo Tu We Th Fr Sa Su
 #  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

Above, week 0 means the week is not considered part of this month. So 1st sept is in the 5th week of august.

NB

I would like to comment on @unutbu answer but I dont have enough points I guess.
The modulo 7 approach fails in sept 2011.

>>> d = datetime.date(2011,9,28)
>>> (d.day-1)//7+1
4
>>> d = datetime.date(2011,9,1)
>>> 
>>> (d.day-1)//7+1
1

from the above calendar, 1st of sept is in week one, but that means the 28th cannot be in week 4 – it must be either in week 5, or 1st is in week 0…

Leave a Comment