Python: номер недели в месяце - PullRequest
8 голосов
/ 11 августа 2011

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

datetime.datetime(2011, 8, 15)

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

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

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

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

Ответы [ 7 ]

10 голосов
/ 11 августа 2011

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

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

Конечно, это означает, что в следующем году 52-я неделя заканчивается не 30 декабря, а 29 декабря. И каждый год происходит спад по одному за раз, до 6-го года, когда мы переместили конец 52-й недели назад на 6 дней (и бросили в високосный день для хорошей меры), так что вся 1-я неделя 2017 года будет содержится в 2016 году, и это было бы глупо. Таким образом, в 2016 году будет 53 недели.

Точно такая же логика применима к месяцам, однако это может быть сложнее обнаружить. К сожалению, вы выбираете август 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 августа на 5-й неделе августа, но с той же логикой 1-е, 2-е, 3-е и 4-е сентября также будут на 5-й неделе августа, и поэтому не могут быть на 1-й неделе сентября.

Таким образом, 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 ...

9 голосов
/ 11 августа 2011
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
2 голосов
/ 11 августа 2011

Этот (несколько неуклюжий) пример использования модуля календаря ...

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, основываясь на ожидании ОП, если недели не начнутся во вторник.

1 голос
/ 13 июля 2017

Как насчет этого.Мы даем дату, на которую мы хотим найти неделю.Мы сбрасываем дату на первый день месяца в новой переменной.Затем мы создаем неделю в году как для первого дня, так и для данной даты.Вычтите первый 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
1 голос
/ 11 августа 2011

Может быть 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
0 голосов
/ 07 декабря 2017

Чтобы принять во внимание комментарий @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

0 голосов
/ 11 августа 2011
testdate = datetime.datetime(2011, 2, 28)
weekofmonth = (testdate.day+7-1)/7

В общем, чтобы найти потолок деления: потолок (х / у) = (х + у-1) / у

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...