python - номер недели месяца

Предлагает ли python способ легко получить текущую неделю месяца (1:4)?


person Joao Figueiredo    schedule 27.09.2010    source источник
comment
Когда вы достигаете 29-го числа, вы на самом деле находитесь на пятой неделе, верно?   -  person erikbwork    schedule 27.09.2010
comment
Неделя начинается в первый день месяца или всегда в понедельник? Или всегда в воскресенье? Или... ?   -  person Mark Byers    schedule 27.09.2010
comment
неделя месяца — не совсем общеупотребительное понятие. Вы должны сообщить нам, каково ваше определение, с примерами, недели месяца ... в частности, недели КАКОГО месяца, например. неделя начинается в понедельник, предположим, что сегодня и воскресенье, и первый день месяца: вы хотите (предыдущий месяц, неделя 5) или (текущий месяц, неделя -1 или 0) или что-то еще?   -  person John Machin    schedule 28.09.2010
comment
Вот одно определение: download-llnw.oracle. com/javase/1.3/docs/api/java/util/   -  person John Machin    schedule 28.09.2010
comment
Ответ Марка Байерса перешел прямо к делу. Я обращаюсь к базе данных Oracle с помощью cx_Oracle и пытаюсь оптимизировать время вычислений, передавая запросы уже с месяцем и неделей месяца (таблица разделена по месяцам и разделена на недели месяца, ссылка на которую John Machin имеет определение как : диапазон поля WEEK_OF_MONTH от .. 1 до .. 5)   -  person Joao Figueiredo    schedule 28.09.2010
comment
Просто чтобы уточнить, это было сделано для того, чтобы избежать использования PARTITION_KEY = ((TO_CHAR(SYSDATE, 'MM'))-1) и SUBPARTITION_WEEK = TO_NUMBER(TO_CHAR(SYSDATE, 'W')) так как это сделало бы недействительным использование индекса. Передача запроса с правильными числами позволяет использовать индексы.   -  person Joao Figueiredo    schedule 28.09.2010


Ответы (15)


Чтобы использовать прямое деление, день месяца для просматриваемой даты необходимо скорректировать в соответствии с положением (в пределах недели) первого дня месяца. Итак, если ваш месяц начинается в понедельник (первый день недели), вы можете просто выполнить деление, как было предложено выше. Однако, если месяц начинается в среду, вам нужно добавить 2, а затем выполнить деление. Все это инкапсулировано в функции ниже.

from math import ceil

def week_of_month(dt):
    """ Returns the week of the month for the specified date.
    """

    first_day = dt.replace(day=1)

    dom = dt.day
    adjusted_dom = dom + first_day.weekday()

    return int(ceil(adjusted_dom/7.0))
person Josh    schedule 29.05.2013
comment
Adjust_dom = (1 + first_day.weekday()) % 7 для недели, начинающейся в воскресенье - person jpoehnelt; 03.03.2014
comment
Работает очень хорошо. Спасибо. - person crazyDiamond; 15.12.2015
comment
Если я хочу искать вторые субботы каждого месяца, это не удастся сделать 7 сентября 2019 года. - person bhushan pardhi; 08.11.2019
comment
для 4 марта 2020 г. возвращается 2, что неверно. Переключено на другое решение ниже: stackoverflow.com/a/26662038/6072151 - person Steve; 08.05.2020
comment
@JustinPoehnelt Я думаю, ты ошибся. Должно быть adjusted_dom = dom + (1 + first_day.weekday()) % 7 - person user3595632; 05.09.2020

Я знаю, что этому много лет, но я потратил много времени, пытаясь найти этот ответ. Я сделал свой собственный метод и подумал, что должен поделиться.

Модуль календаря имеет метод monthcalendar, который возвращает двумерный массив, где каждая строка представляет неделю. Например:

import calendar
calendar.monthcalendar(2015,9)

результат:

[[0,0,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,0,0,0]]

Итак, numpy, где твой друг здесь. И я в США, поэтому я хочу, чтобы неделя начиналась в воскресенье, а первая неделя была помечена как 1:

import calendar
import numpy as np
calendar.setfirstweekday(6)

def get_week_of_month(year, month, day):
    x = np.array(calendar.monthcalendar(year, month))
    week_of_month = np.where(x==day)[0][0] + 1
    return(week_of_month)

get_week_of_month(2015,9,14)

возвращается

3
person Texas P Renegade    schedule 15.09.2015
comment
извините, я новичок в этом. Как использовать эту функцию для получения номера недели текущей даты вместо вставки точного года, месяца и даты? - person RSM; 10.05.2020
comment
@RSM - просто используйте datetime.today().year/month/day :-) - person Václav; 15.06.2020
comment
использование numpy для этой функции является излишним - на мой взгляд. - person Tony Suffolk 66; 18.09.2020

Если ваша первая неделя начинается в первый день месяца, вы можете использовать целочисленное деление:

import datetime
day_of_month = datetime.datetime.now().day
week_number = (day_of_month - 1) // 7 + 1
person Mark Byers    schedule 27.09.2010
comment
возможно, datetime.datetime.now().day даст сегодняшний день в месяце - person aeter; 27.09.2010
comment
Спасибо. Оказывается, дело было не в Python, а в арифметике :) - person Joao Figueiredo; 28.09.2010
comment
Мне непонятно, работает ли это. Предположим, что ваша неделя начинается в понедельник, а 1-е число интересующего месяца — воскресенье, вы хотите, чтобы день месяца 1 сопоставлялся с неделей месяца 1. В этом случае приведенный выше алгоритм вернет правильный ответ. Однако, если вы перейдете ко второму дню, понедельнику 2-го числа, вы захотите, чтобы алгоритм вернул 2. В этом случае алгоритм возвращает неправильный ответ. См. мой ответ ниже, который возвращает правильный результат в обоих случаях с учетом смещения. - person Josh; 29.05.2013
comment
Это не подходит для случая с датой 10 февраля 2020 года, а также для большинства других случаев. Это не общий случай. - person saravanan saminathan; 11.03.2020

Ознакомьтесь с пакетом Pendulum

>>> dt = pendulum.parse('2018-09-30')
>>> dt.week_of_month
5
person Prateek Dorwal    schedule 16.11.2018
comment
Я использовал это решение до тех пор, пока даты 2021-01-10, 2021-01-17, 2021-01-24, 2021-01-31 не возвращали минус значения соответственно: -51, -50, -49, - 48.. Так что глючит как-то. - person Gunner1905; 06.07.2021

Эта версия может быть улучшена, но в качестве первого взгляда на модули Python (дата, время и календарь) я делаю это решение, надеюсь, оно может быть полезным:

from datetime import datetime
n = datetime.now()
#from django.utils.timezone import now
#n = now() #if you use django with timezone

from calendar import Calendar
cal = Calendar() # week starts Monday
#cal = Calendar(6) # week stars Sunday

weeks = cal.monthdayscalendar(n.year, n.month)
for x in range(len(weeks)):
    if n.day in weeks[x]:
        print x+1
person Manuel    schedule 30.10.2014
comment
что такое now переменная? - person user1234440; 01.06.2020

Ознакомьтесь с модулем python календаря.

person vito huang    schedule 27.09.2010
comment
Спасибо. Я знал о calendar и dateutil, но оба мне в этом не помогли. - person Joao Figueiredo; 28.09.2010
comment
Вито имеет правильный ответ. Я использовал: st, end = calendar.monthrange(2012, 6), days = range(st, end+1), week_days = [days[i : i+7] for i in range(0, len(days), 7)] - person Droogans; 06.06.2012
comment
Предоставление ссылки не является ответом на вопрос. - person pishpish; 08.08.2019

Ответ Джоша нужно немного изменить, чтобы он соответствовал первому дню, выпавшему на воскресенье.

def get_week_of_month(date):
   first_day = date.replace(day=1)

   day_of_month = date.day

   if(first_day.weekday() == 6):
       adjusted_dom = (1 + first_day.weekday()) / 7
   else:
       adjusted_dom = day_of_month + first_day.weekday()

   return int(ceil(adjusted_dom/7.0))
person crazyDiamond    schedule 15.12.2015

Я нашел довольно простой способ:

import datetime
def week(year, month, day):
    first_week_month = datetime.datetime(year, month, 1).isocalendar()[1]
    if month == 1 and first_week_month > 10:
        first_week_month = 0
    user_date = datetime.datetime(year, month, day).isocalendar()[1]
    if month == 1 and user_date > 10:
        user_date = 0
    return user_date - first_week_month

возвращает 0, если первая неделя

person Manuel Cuadra Leighton    schedule 06.12.2010
comment
isocalendar() может вернуть 53 для 1 января. Ваша реализация возвращает -52 для weekOfMonth(2010, 1, 8). - person Adam Rosenfield; 07.12.2010
comment
Я исправил код с проверкой этой ошибки, и код не становится таким большим, и он отлично справляется со своей задачей. - person Manuel Cuadra Leighton; 07.12.2010
comment
Возвращает -47 для дат: 2012-12-31, 2013-12-30, 2013-12-31 - person nu everest; 26.01.2013
comment
Возвращает -48 для дат: 2014-12-29, 2014-12-30, 2014-12-31 - person nu everest; 26.01.2013

Ответ Джоша кажется лучшим, но я думаю, что мы должны учитывать тот факт, что неделя принадлежит месяцу только в том случае, если ее четверг приходится на этот месяц. По крайней мере, это что говорит iso.

По этому стандарту в месяце может быть до 5 недель. День может принадлежать месяцу, но неделя, которой он принадлежит, может не принадлежать.

Я принял во внимание, что просто добавив простой

if (first_day.weekday()>3) :
        return ret_val-1
    else:
        return ret_val

где ret_val — точно вычисленное значение Джоша. Протестировано в июне 2017 г. (имеет 5 недель) и в сентябре 2017 г. Передача «2017-09-01» возвращает 0, поскольку этот день принадлежит неделе, которая не принадлежит сентябрю.

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

person benelgiac    schedule 22.09.2017

def week_of_month(date_value):
 return (date_value.isocalendar()[1] - date_value.replace(day=1).isocalendar()[1] + 1)

date_value должен быть в формате метки времени. Это даст идеальный ответ во всех случаях.

person saravanan saminathan    schedule 11.03.2020

Вариант ответа @Manuel Solorzano:

from calendar import monthcalendar
def get_week_of_month(year, month, day):
    return next(
        (
            week_number
            for week_number, days_of_week in enumerate(monthcalendar(year, month), start=1)
            if day in days_of_week
        ),
        None,
    )

E.g.:

>>> get_week_of_month(2020, 9, 1)
1
>>> get_week_of_month(2020, 9, 30)
5
>>> get_week_of_month(2020, 5, 35)
None
person vekerdyb    schedule 01.09.2020

Скажем, у нас есть календарь на месяц следующим образом:

Mon Tue Wed Thur Fri Sat Sun
                 1   2   3 
4   5   6   7    8   9   10

Мы говорим, что день 1–3 относится к неделе 1, а день 4–10 относится к неделе 2 и т. д.

В этом случае я считаю, что week_of_month для определенного дня следует рассчитывать следующим образом:

import datetime
def week_of_month(year, month, day):
    weekday_of_day_one = datetime.date(year, month, 1).weekday()
    weekday_of_day = datetime.date(year, month, day)
    return (day - 1)//7 + 1 + (weekday_of_day < weekday_of_day_one)

Однако, если вместо этого мы хотим получить n-й день недели, которым является эта дата, например, день 1 — это 1-я пятница, день 8 — это 2-я пятница, а день 6 — это 2-я пятница. 1-я среда, то мы можем просто вернуть (day - 1)//7 + 1

person Lin Jingjing    schedule 18.09.2020
comment
Это работает хорошо, но нам нужно: weekday_of_day = datetime.date(год, месяц, день).weekday() - person yeharav; 10.10.2020

Это должно сделать это.

#! /usr/bin/env python2

import calendar, datetime

#FUNCTIONS
def week_of_month(date):
    """Determines the week (number) of the month"""

    #Calendar object. 6 = Start on Sunday, 0 = Start on Monday
    cal_object = calendar.Calendar(6)
    month_calendar_dates = cal_object.itermonthdates(date.year,date.month)

    day_of_week = 1
    week_number = 1

    for day in month_calendar_dates:
        #add a week and reset day of week
        if day_of_week > 7:
            week_number += 1
            day_of_week = 1

        if date == day:
            break
        else:
            day_of_week += 1

    return week_number


#MAIN
example_date = datetime.date(2015,9,21)

print "Week",str(week_of_month(example_date))
#Returns 'Week 4'
person Dan    schedule 22.09.2015

Перейти к последнему дню недели в месяце и разделить на 7

from math import ceil

def week_of_month(dt):
    """ Returns the week of the month for the specified date.
    """
    # weekday from monday == 0 ---> sunday == 6
    last_day_of_week_of_month = dt.day + (7 - (1 + dt.weekday()))
    return int(ceil(last_day_of_week_of_month/7.0))
person Tan Nguyen    schedule 27.03.2019

Искомый ответ: (dm-dw+(dw-dm)%7)/7+1, где dm — день месяца, dw — день недели, а % — положительный остаток.

Это происходит из соотношения смещения месяца (mo) и недели месяца (wm), где смещение месяца — это то, как далеко в неделе начинается первый день. Если мы считаем, что все эти переменные начинаются с 0, мы имеем

wm*7+dw = dm+mo

Вы можете решить это по модулю 7 для mo, так как это приводит к тому, что переменная wm выпадает, поскольку она появляется только как кратная 7

dw = dm+mo   (%7)
mo = dw-dm   (%7)
mo = (dw-dm)%7  (since the month offset is 0-6)

Затем вы просто подставляете смещение месяца в исходное уравнение и решаете для wm

wm*7+dw = dm+mo
wm*7 = dm-dw + mo
wm*7 = dm-dw + (dw-dm)%7
wm = (dm-dw + (dw-dm)%7) / 7

Поскольку dm и dw всегда являются парными, они могут быть смещены на любую величину, поэтому переключение всего, чтобы начать с 1, только меняет уравнение на (dm-dw + (dw-dm)%7)/7 + 1.

Конечно, библиотека python datetime начинается с dm с 1 и dw с 0. Итак, если предположить, что date является объектом datatime.date, вы можете пойти с

(date.day-1-date.dayofweek() + (date.dayofweek()-date.day+1)%7) / 7 + 1

Поскольку внутренний бит всегда кратен 7 (это буквально dw*7), вы можете видеть, что первый -date.dayofweek() просто корректирует значение в обратном направлении до ближайшего кратного 7. Целочисленное деление тоже делает это, поэтому его можно еще упростить до

(date.day-1 + (date.dayofweek()-date.day+1)%7) // 7 + 1

Имейте в виду, что dayofweek() помещает воскресенье в конец недели.

person Tyson Whitehead    schedule 12.02.2021