Как получить номер недели в Python?


339

Как узнать, какой номер недели является текущим годом 16 июня (wk24) с Python?


1
@Donal: Один смотрит на 16 июня, другой на 26 июня
межджай

5
Определите неделю 1. isocalendar () - не единственный способ сделать это.
Марк Толонен

3
Обратите внимание, что выходные данные strftime("%U", d)могут отличаться от isocalendar(). Например, если вы измените год на 2004, вы получите неделю 24, strftime()а неделю 25 - isocalendar().
moooeeeep

Ответы:


409

datetime.dateимеет isocalendar()метод, который возвращает кортеж, содержащий календарную неделю:

>>> import datetime
>>> datetime.date(2010, 6, 16).isocalendar()[1]
24

datetime.date.isocalendar () - это метод экземпляра, возвращающий кортеж, содержащий год, номер недели и день недели в соответствующем порядке для данного экземпляра даты.


7
Было бы полезно, если бы вы объяснили « [1]» или указали, где искать информацию.
Джонатан Леффлер

5
Я полагаю, что самое простое - это извлечь номер недели, используя strftime, лучший импорт datetime сегодня = datetime.now () week = today.strftime ("% W")
bipsa

7
Это немного поздно. Но на моей машине date(2010, 1, 1).isocalendar()[1]возвращается 53. Из документов: «Например, 2004 год начинается в четверг, поэтому первая неделя ИСО 2004 года начинается в понедельник, 29 декабря 2003 года, и заканчивается в воскресенье, 4 января 2004 года, так что date(2003, 12, 29).isocalendar() == (2004, 1, 1)и date(2004, 1, 4).isocalendar() == (2004, 1, 7)».
jclancy

17
isocalendar()это здорово, но будь уверен, что это то, что ты хочешь. Сегодня прекрасный пример. 01.01.2016 равняется (2015, 53, 5). now.strftime("%W")и now.strftime("%U")равны 00которым часто то, что нужно. Примеры STRFTIME
DaveL17

хороший, я только что добавил сегодняшний день, я думаю, что это будет полезно, это то, к чему я стремился: D
Виталий Терзиев

124

Вы можете получить номер недели непосредственно из datetime в виде строки.

>>> import datetime
>>> datetime.date(2010, 6, 16).strftime("%V")
'24'

Также вы можете получить различные «типы» номера недели в году, изменяя strftimeпараметр для:

%U- Номер недели в году (воскресенье - первый день недели) в виде десятичного числа с добавлением нуля. Все дни в новом году, предшествующем первому воскресенью, считаются неделей 0. Примеры: 00 , 01,…, 53

%W- Номер недели в году ( понедельник - первый день недели) в виде десятичного числа. Все дни в новом году, предшествующем первому понедельнику, считаются неделей 0. Примеры: 00 , 01,…, 53

[...]

( Добавлено в Python 3.6, перенесено в некоторые дистрибутивы Python 2.7 ). Для удобства включены несколько дополнительных директив, не требуемых стандартом C89. Все эти параметры соответствуют значениям даты ISO 8601. Они могут быть недоступны на всех платформах при использовании с strftime()методом.

[...]

%V- неделя ISO 8601 в виде десятичного числа с понедельником в качестве первого дня недели. Неделя 01 - это неделя, содержащая 4 января. Примеры: 01 , 02,…, 53

from: datetime - Основные типы даты и времени - Документация Python 3.7.3

Я узнал об этом отсюда . У меня это работает в Python 2.7.6


Что вы цитируете, какое-то руководство по Linux? Python 2.7.5 и 3.3.2 говорят Invalid format stringоб этом шаблоне. Их документы тоже не упоминаются %V.
Всеволод Голованов

3
Извините, я не упомянул об этом, я получил отсюда . У меня это работало в Python 2.7.6.
Jotacor

2
Отличный ответ! Я хотел бы добавить, что если вас интересует представление ваших дат в «<YEAR> - <ISOWEEK>», используйте %G-%Vвместо %Y-%V. %Gгодовой эквивалент ISO%Y
KenHBS

Я должен был написать это так, чтобы он работал: datetime.datetime (2010, 6, 16) .strftime ("% V") или как этот datetime.datetime (2010, 6, 16) .date (). Strftime ("% V")
Эйнар

77

Я верю, что date.isocalendar()это будет ответом. Эта статья объясняет математику календаря ISO 8601. Проверьте часть date.isocalendar () страницы datetime в документации Python.

>>> dt = datetime.date(2010, 6, 16) 
>>> wk = dt.isocalendar()[1]
24

.isocalendar () возвращает 3 кортежа с (год, недельный номер, недельный день). dt.isocalendar()[0]возвращает год, dt.isocalendar()[1]возвращает номер недели, dt.isocalendar()[2]возвращает день недели. Просто, как может быть.


4
+1 за ссылку, которая объясняет неинтуитивный характер недель ISO.
Марк Рэнсом

27

Вот еще один вариант:

import time
from time import gmtime, strftime
d = time.strptime("16 Jun 2010", "%d %b %Y")
print(strftime("%U", d))

который печатает 24.

Смотрите: http://docs.python.org/library/datetime.html#strftime-and-strptime-behavior


9
или% W, если ваши недели начинаются по понедельникам.
ZeWaren

1
Этот подход лучше в случаях, когда вы не хотите разделять или преобразовывать дату, которая появляется в виде строки ... просто передайте строку в strptime в формате строки как есть и укажите формат во втором аргументе. Хорошее решение Помните:% W, если неделя начинается по понедельникам.
TheCuriousOne

22

Неделя ISO, предложенная другими, - хорошая, но она может не соответствовать вашим потребностям. Предполагается, что каждая неделя начинается с понедельника, что приводит к некоторым интересным аномалиям в начале и конце года.

Если вы предпочитаете использовать определение, которое гласит, что неделя 1 всегда 1 января - 7 января, независимо от дня недели, используйте деривацию, подобную этой:

>>> testdate=datetime.datetime(2010,6,16)
>>> print(((testdate - datetime.datetime(testdate.year,1,1)).days // 7) + 1)
24

3
Сказать, что в начале и конце года isocalendar имеет «некоторые интересные аномалии», кажется немного преуменьшением. Результаты isocalendar очень вводят в заблуждение (даже если они не являются действительно неправильными в соответствии со спецификацией ISO) для некоторых значений даты и времени, таких как 29 декабря 2014 г., 00:00:00, которые согласно isocalendar имеют годовое значение 2015 и weekNumber 1 (см. моя запись ниже).
Кевин

3
@ Кевин, это не так, просто их определения не совпадают с вашими. ИСО решила две вещи: во-первых, всю неделю с понедельника по воскресенье будет в одном и том же году, во-вторых, назначенный год, содержащий большинство дней. Это приводит к дням недели вокруг начала и конца года, которые переходят в соседний год.
Марк Рэнсом

6
Согласовано. Но по определению большинства людей 29 декабря 2014 года определенно не будет первой неделей 2015 года. Я просто хотел привлечь внимание к этому потенциальному источнику путаницы.
Кевин

Это именно то, что я искал. Не о том, как это сделать, а о том, что касается ISO и как начать с понедельника.
Амит Амола

19

Как правило, чтобы получить номер текущей недели (начинается с воскресенья):

from datetime import *
today = datetime.today()
print today.strftime("%U")

4
Из документации strftime ('% U'): «Номер недели в году (воскресенье как первый день недели) в виде десятичного числа [00,53]. Все дни в новом году, предшествующие первому воскресенью, считаются быть на неделе 0. "
Долан Антенуччи

14

Для целочисленного значения мгновенной недели года попробуйте:

import datetime
datetime.datetime.utcnow().isocalendar()[1]

11

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

  • ISO : первая неделя начинается с понедельника и должна содержать 4 января. Календарь ISO уже реализован на Python:

    >>> from datetime import date
    >>> date(2014, 12, 29).isocalendar()[:2]
    (2015, 1)
  • Северная Америка : первая неделя начинается с воскресенья и должна содержать 1 января. Следующий код является моей модифицированной версией реализации календаря Python ISO для системы в Северной Америке:

    from datetime import date
    
    def week_from_date(date_object):
        date_ordinal = date_object.toordinal()
        year = date_object.year
        week = ((date_ordinal - _week1_start_ordinal(year)) // 7) + 1
        if week >= 52:
            if date_ordinal >= _week1_start_ordinal(year + 1):
                year += 1
                week = 1
        return year, week
    
    def _week1_start_ordinal(year):
        jan1 = date(year, 1, 1)
        jan1_ordinal = jan1.toordinal()
        jan1_weekday = jan1.weekday()
        week1_start_ordinal = jan1_ordinal - ((jan1_weekday + 1) % 7)
        return week1_start_ordinal
    >>> from datetime import date
    >>> week_from_date(date(2014, 12, 29))
    (2015, 1)
  • MMWR (CDC) : первая неделя начинается с воскресенья и должна содержать 4 января. Я создал пакет epiweeks специально для этой системы нумерации (также есть поддержка системы ISO). Вот пример:
    >>> from datetime import date
    >>> from epiweeks import Week
    >>> Week.fromdate(date(2014, 12, 29))
    (2014, 53)

8

Если вы используете только номер недели isocalendar через доску, этого должно быть достаточно:

import datetime
week = date(year=2014, month=1, day=1).isocalendar()[1]

Это извлекает второго члена кортежа, возвращенного isocalendar для нашего номера недели.

Однако, если вы собираетесь использовать функции даты, которые имеют дело с григорианским календарем, isocalendar один не будет работать! Возьмите следующий пример:

import datetime
date = datetime.datetime.strptime("2014-1-1", "%Y-%W-%w")
week = date.isocalendar()[1]

Строка здесь говорит, чтобы вернуть понедельник первой недели 2014 года в качестве нашей даты. Когда мы используем isocalendar для получения номера недели здесь, мы ожидаем получить тот же номер недели назад, но мы этого не делаем. Вместо этого мы получаем номер недели 2. Почему?

Неделя 1 в григорианском календаре - это первая неделя, содержащая понедельник. Неделя 1 в isocalendar - это первая неделя, содержащая четверг. Неполная неделя в начале 2014 года содержит четверг, так что isocalendar это неделя 1, а dateнеделя 2.

Если мы хотим получить григорианскую неделю, нам нужно будет перейти с isocalendar на григорианский. Вот простая функция, которая делает свое дело.

import datetime

def gregorian_week(date):
    # The isocalendar week for this date
    iso_week = date.isocalendar()[1]

    # The baseline Gregorian date for the beginning of our date's year
    base_greg = datetime.datetime.strptime('%d-1-1' % date.year, "%Y-%W-%w")

    # If the isocalendar week for this date is not 1, we need to 
    # decrement the iso_week by 1 to get the Gregorian week number
    return iso_week if base_greg.isocalendar()[1] == 1 else iso_week - 1

6

Вы можете попробовать директиву% W, как показано ниже:

d = datetime.datetime.strptime('2016-06-16','%Y-%m-%d')
print(datetime.datetime.strftime(d,'%W'))

«% W»: номер недели в году (понедельник - первый день недели) в виде десятичного числа. Все дни в новом году, предшествующем первому понедельнику, считаются неделей 0. (00, 01, ..., 53)


2

isocalendar () возвращает неправильные значения года и номера недели для некоторых дат:

Python 2.7.3 (default, Feb 27 2014, 19:58:35) 
[GCC 4.6.3] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import datetime as dt
>>> myDateTime = dt.datetime.strptime("20141229T000000.000Z",'%Y%m%dT%H%M%S.%fZ')
>>> yr,weekNumber,weekDay = myDateTime.isocalendar()
>>> print "Year is " + str(yr) + ", weekNumber is " + str(weekNumber)
Year is 2015, weekNumber is 1

Сравните с подходом Марка Рэнсома:

>>> yr = myDateTime.year
>>> weekNumber = ((myDateTime - dt.datetime(yr,1,1)).days/7) + 1
>>> print "Year is " + str(yr) + ", weekNumber is " + str(weekNumber)
Year is 2014, weekNumber is 52

3
Просматривая некоторые ссылки о календаре iso8601 (например, staff.science.uu.nl/~gent0113/calendar/isocalendar.htm ), я вижу, что значения года и номера недели, возвращаемые функцией isocalendar (), не являются «неправильными» как таковые. В соответствии с ISO8601, например, 2004 год начался 29 декабря 2003 года. Поэтому isocalendar () может быть правильным, если возвращать год 2015 для 29 декабря 2014 года, но для многих людей это будет довольно обманчиво. ,
Кевин

2

Я суммирую обсуждение в два этапа:

  1. Преобразуйте необработанный формат в datetimeобъект.
  2. Используйте функцию datetimeобъекта или dateобъекта для вычисления номера недели.

Разогрев

`` `` Питон

from datetime import datetime, date, time
d = date(2005, 7, 14)
t = time(12, 30)
dt = datetime.combine(d, t)
print(dt)

`` `

1-й шаг

Чтобы вручную создать datetimeобъект, мы можем использовать datetime.datetime(2017,5,3)илиdatetime.datetime.now() .

Но на самом деле нам обычно нужно проанализировать существующую строку. Мы можем использовать strptimeфункцию, например, datetime.strptime('2017-5-3','%Y-%m-%d')в которой вы должны указать конкретный формат. Детали кода различного формата можно найти в официальной документации .

В качестве альтернативы, более удобный способ - использовать модуль dateparse . Примеры dateparser.parse('16 Jun 2010'), dateparser.parse('12/2/12')илиdateparser.parse('2017-5-3')

Два вышеупомянутых подхода вернут datetimeобъект.

2-й шаг

Используйте полученный datetimeобъект для вызова strptime(format). Например,

`` `` Питон

dt = datetime.strptime('2017-01-1','%Y-%m-%d') # return a datetime object. This day is Sunday
print(dt.strftime("%W")) # '00' Monday as the 1st day of the week. All days in a new year preceding the 1st Monday are considered to be in week 0.
print(dt.strftime("%U")) # '01' Sunday as the 1st day of the week. All days in a new year preceding the 1st Sunday are considered to be in week 0.
print(dt.strftime("%V")) # '52' Monday as the 1st day of the week. Week 01 is the week containing Jan 4.

`` `

Очень сложно решить, какой формат использовать. Лучший способ - получить dateобъект для вызова isocalendar(). Например,

`` `` Питон

dt = datetime.strptime('2017-01-1','%Y-%m-%d') # return a datetime object
d = dt.date() # convert to a date object. equivalent to d = date(2017,1,1), but date.strptime() don't have the parse function
year, week, weekday = d.isocalendar() 
print(year, week, weekday) # (2016,52,7) in the ISO standard

`` `

На самом деле, вы будете чаще использовать date.isocalendar()для подготовки еженедельного отчета, особенно в сезон покупок "Рождество-Новый год".


0
userInput = input ("Please enter project deadline date (dd/mm/yyyy/): ")

import datetime

currentDate = datetime.datetime.today()

testVar = datetime.datetime.strptime(userInput ,"%d/%b/%Y").date()

remainDays = testVar - currentDate.date()

remainWeeks = (remainDays.days / 7.0) + 1


print ("Please pay attention for deadline of project X in days and weeks are  : " ,(remainDays) , "and" ,(remainWeeks) , "Weeks ,\nSo  hurryup.............!!!") 

-1

Было дано много ответов, но я хотел бы добавить к ним.

Если вам нужна неделя для отображения в формате год / неделя (например, 1953 год - неделя 53 от 2019 года, 2001 год - неделя 1 от 2020 года и т. Д.), Вы можете сделать это:

import datetime

year = datetime.datetime.now()
week_num = datetime.date(year.year, year.month, year.day).strftime("%V")
long_week_num = str(year.year)[0:2] + str(week_num)

Это займет текущий год и неделю, а long_week_num в день написания будет:

>>> 2006

Зачем создавать date()с нуля? datetime.datetime()экземпляры имеют .date()метод для этой работы.
Мартин Питерс

Однако более тревожным является то, что ваш ответ выбирает столетие , а не текущий год. И если вы собираетесь использовать форматирование строки для номера недели, то почему бы не использовать это для включения года?
Мартин Питерс
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.