Python: количество недель в месяце

при указании даты:

datetime.datetime(2011, 8, 15)

Как я могу узнать, что это третья недели месяца?

что если я хочу этой даты?

datetime.datetime(2011, 2, 28) //should return 4
datetime.datetime(2011, 8, 29) //should return 5

Я понимаю, что только февраль имеет 4 недели, Если данная дата находится в високосном году (bissextile)

7 ответов


In [115]: d=datetime.datetime(2011, 2, 28)

In [116]: (d.day-1)//7+1
Out[116]: 4

In [117]: d=datetime.datetime(2011, 8, 29)

In [118]: (d.day-1)//7+1
Out[118]: 5

подход по модулю, показанный в других ответах, может вводить в заблуждение. Представьте себе недели в году. Есть 52 куска 7 дней в любом 365-дневном году, с одним днем, оставшимся. Итак, если для моего первого года 52-я неделя заканчивается 30 декабря, и мне остается беспокоиться о 31 декабря.

Я могу или считайте, что в году 53 недели, а 53-я неделя-31 декабря, 1 января, 2 января, 3 января ... Или, более условно, я считаю, что первая неделя следующей год фактически начинается 31 декабря. Вот как это делает ваш дневник pocket book.

точно такая же логика применяется к месяцам, однако ее может быть труднее обнаружить. К сожалению, вы выбираете август 2011, который имеет аккуратное расположение начала 1-го числа месяца в понедельник.

>>> 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 сентября будет, по простому числу деления дней на 7 подход, быть в 5-ю неделю если 1-4 сентября приходится на август, то 29 сентября приходится на 4-ю неделю сентября.

все зависит от вашего определения того, когда начинается Неделя.

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

выше, неделя 0 означает, что неделя не считается частью этого месяца. Итак, 1 сентября-5 августа.

NB

Я хотел бы прокомментировать ответ @unutbu, но у меня недостаточно очков, я думаю. Подход по модулю 7 терпит неудачу в сентябре 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

из вышеприведенного календаря 1 сентября находится на первой неделе, но это означает, что 28-е не может быть на 4 - й неделе-это должно быть либо на 5-й неделе, либо 1-й на 0-й неделе...


Это (немного корявый), например, с помощью модуля "календарь"...

import calendar
import datetime

def week(dt):
    mth = calendar.monthcalendar(dt.year, dt.month)
    for i, wk in enumerate(mth):
        if dt.day in wk:
            return i + 1

calendar.setfirstweekday(calendar.MONDAY)

week(datetime.datetime(2011, 8, 15)) # 3
week(datetime.datetime(2011, 2, 28)) # 5
week(datetime.datetime(2011, 8, 29)) # 5

... получает неправильный ответ на 2011-02-28, основываясь на ожиданиях ОП, Если недели не начнутся во вторник.


может быть http://labix.org/python-dateutil поможет.

кроме этого, это просто математика.

 from datetime import datetime, timedelta

    def week_of_month(date):
        month = date.month
        week = 0
        while date.month == month:
            week += 1
            date -= timedelta(days=7)

        return week

Как насчет этого. Мы даем дату, на которую мы хотим найти неделю. Мы сбрасываем дату в первый день месяца в новой переменной. Затем мы создаем неделю в году как для первого дня, так и для заданной даты. Вычесть первый isoweek из isoweek данной даты и добавить один. Вы добавляете один, чтобы исправить нулевой индекс. Это должно дать номер недели в месяце.

import datetime

def _get_week_of_day(date):
    first_day = date.replace(day=1)
    iso_day_one = first_day.isocalendar()[1]
    iso_day_date = date.isocalendar()[1]
    adjusted_week = (iso_day_date - iso_day_one) + 1
    return adjusted_week

testdate = datetime.datetime(2011, 2, 28)
weekofmonth = (testdate.day+7-1)/7

В общем найти потолок деления: потолок (x/y) = (x+y-1) / y


чтобы учесть комментарий @Usagi:

datetime.datetime(2011, 8, 15) // should return 3
datetime.datetime(2011, 2, 28) // should return 5
datetime.datetime(2011, 8, 29) // should return 5

следующее уравнение управляет тем, что первый день месяца не нужен понедельник:

(d.day-d.weekday() -2)//7+2

-2 и +2 позволяют получить номер недели между 1 и 6