How to get week number in Python?
Asked Answered
L

20

511

How to find out what week number is current year on June 16th (wk24) with Python?

Leslee answered 8/4, 2010 at 14:35 Comment(3)
@Donal: One looks at June 16, the other at June 26.Cassiecassil
Define week 1. isocalendar() is not the only way to do it.Keys
Note that the output of strftime("%U", d) may differ from the isocalendar(). For example if you change the year to 2004 you'd get week 24 using strftime() and week 25 using isocalendar().Dantedanton
D
649

datetime.date has a isocalendar() method, which returns a tuple containing the calendar week:

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

datetime.date.isocalendar() is an instance-method returning a tuple containing year, weeknumber and weekday in respective order for the given date instance.

In Python 3.9+ isocalendar() returns a namedtuple with the fields year, week and weekday which means you can access the week explicitly using a named attribute:

>>> import datetime
>>> datetime.date(2010, 6, 16).isocalendar().week
24
Dehydrogenate answered 8/4, 2010 at 14:47 Comment(4)
I guess the easiest is extract the week number using strftime, best import datetime today = datetime.now() week = today.strftime("%W")Spoil
This is a little late. But on my machine, date(2010, 1, 1).isocalendar()[1] returns 53. From the docs: "For example, 2004 begins on a Thursday, so the first week of ISO year 2004 begins on Monday, 29 Dec 2003 and ends on Sunday, 4 Jan 2004, so that date(2003, 12, 29).isocalendar() == (2004, 1, 1) and date(2004, 1, 4).isocalendar() == (2004, 1, 7)."Flitter
isocalendar() is great, but be sure it's what you want. Today is a perfect example. 01/01/2016 is equal to (2015, 53, 5). now.strftime("%W") and now.strftime("%U") are equal to 00 which is often what is wanted. STRFTIME examplesRectory
datetime.utcnow().isocalendar().weekGloat
S
226

You can get the week number directly from datetime as string.

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

Also you can get different "types" of the week number of the year changing the strftime parameter for:

%U - Week number of the year (Sunday as the first day of the week) as a zero padded decimal number. All days in a new year preceding the first Sunday are considered to be in week 0. Examples: 00, 01, …, 53

%W - Week number of the year (Monday as the first day of the week) as a decimal number. All days in a new year preceding the first Monday are considered to be in week 0. Examples: 00, 01, …, 53

[...]

(Added in Python 3.6, backported to some distribution's Python 2.7's) Several additional directives not required by the C89 standard are included for convenience. These parameters all correspond to ISO 8601 date values. These may not be available on all platforms when used with the strftime() method.

[...]

%V - ISO 8601 week as a decimal number with Monday as the first day of the week. Week 01 is the week containing Jan 4. Examples: 01, 02, …, 53

from: datetime — Basic date and time types — Python 3.7.3 documentation

I've found out about it from here. It worked for me in Python 2.7.6

Silage answered 21/1, 2015 at 14:15 Comment(5)
What are you quoting, some Linux manual? Python 2.7.5 and 3.3.2 say Invalid format string to this pattern. Their docs don't mention %V either.Furuncle
Sorry I didn't mention it, I've got from here. It worked for me in Python 2.7.6.Silage
Great answer! I'd like to add that if you are interested in a '<YEAR>-<ISOWEEK>' representation of your dates, use %G-%V instead of %Y-%V. %G is the ISO year equivalent of %YMoisesmoishe
I had to write it like this for it to work: datetime.datetime(2010, 6, 16).strftime("%V"), or like this datetime.datetime(2010, 6, 16).date().strftime("%V")Corniculate
How do you apply this solution to an entire dataframe column?Innuendo
P
87

I believe date.isocalendar() is going to be the answer. This article explains the math behind ISO 8601 Calendar. Check out the date.isocalendar() portion of the datetime page of the Python documentation.

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

.isocalendar() return a 3-tuple with (year, wk num, wk day). dt.isocalendar()[0] returns the year,dt.isocalendar()[1] returns the week number, dt.isocalendar()[2] returns the week day. Simple as can be.

Padget answered 8/4, 2010 at 14:48 Comment(1)
+1 for the link which explains the non-intuitive nature of ISO weeks.Tipsy
E
39

There are many systems for week numbering. The following are the most common systems simply put with code examples:

  • ISO: First week starts with Monday and must contain the January 4th (or first Thursday of the year). The ISO calendar is already implemented in Python:

    >>> from datetime import date
    >>> date(2014, 12, 29).isocalendar()[:2]
    (2015, 1)
    
  • North American: First week starts with Sunday and must contain the January 1st. The following code is my modified version of Python's ISO calendar implementation for the North American system:

    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): First week starts with Sunday and must contain the January 4th (or first Wednesday of the year). I created the epiweeks package specifically for this numbering system (also has support for the ISO system). Here is an example:

    >>> from datetime import date
    >>> from epiweeks import Week
    >>> Week.fromdate(date(2014, 12, 29))
    (2014, 53)
    
Enid answered 29/6, 2019 at 16:23 Comment(1)
This is the best answer to the question, because it takes into account the year number and the different week numbering standards.Azoic
A
34

Here's another option:

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

which prints 24.

See: http://docs.python.org/library/datetime.html#strftime-and-strptime-behavior

Alexipharmic answered 8/4, 2010 at 14:50 Comment(5)
or %W if your weeks start on Mondays.Kolinsky
This approach is better in cases where you don't want to split or convert a date which comes as a string... just pass the string in strptime in string format as it is and specify the format in second argument. Good solution. Remember: %W if week starts on Mondays.Valene
This works for me! I was having problems with the datetime datetime.datetime(2019, 12, 30) using the above answers, which gave me 1, but this gives the correct week.Craiova
TypeError: strftime() argument 1 must be str, not time.struct_timeBuonomo
I'd just add int(), thus: print(int(strftime(d, '%U'))) to avoid leading zeros.Shannon
T
27

The ISO week suggested by others is a good one, but it might not fit your needs. It assumes each week begins with a Monday, which leads to some interesting anomalies at the beginning and end of the year.

If you'd rather use a definition that says week 1 is always January 1 through January 7, regardless of the day of the week, use a derivation like this:

>>> testdate=datetime.datetime(2010,6,16)
>>> print(((testdate - datetime.datetime(testdate.year,1,1)).days // 7) + 1)
24
Tipsy answered 9/4, 2010 at 15:52 Comment(4)
Saying that isocalendar has "some interesting anomalies" at the beginning and end of the year seems to be a bit of an understatement. isocalendar's results are very misleading (even if not actually incorrect under the ISO specification) for some datetime values, like December 29, 2014, 00:00:00, which according to isocalendar has a year value of 2015 and a weekNumber of 1 (see my entry below).Shandrashandrydan
@Kevin, it's not wrong, it's just that their definitions don't match yours. ISO decided two things: first that the entire week Monday through Sunday would be in the same year, second that the year containing most of the days would be the one assigned. This leads to days of the week around the beginning and end of the year that move into the adjoining year.Tipsy
Agreed. But by most people's definition, December 29 2014 will most definitely not be week 1 of the year 2015. I just wanted to draw attention to this potential source of confusion.Shandrashandrydan
This is exactly what I was looking for. Not about how to do this, but the information regarding the ISO and starting with monday thing.Lichenin
H
25

Generally to get the current week number (starts from Sunday):

from datetime import *
today = datetime.today()
print today.strftime("%U")
Horrocks answered 9/3, 2011 at 11:33 Comment(1)
From the documentation of strftime('%U'): "Week number of the year (Sunday as the first day of the week) as a decimal number [00,53]. All days in a new year preceding the first Sunday are considered to be in week 0."Myotonia
K
16

For the integer value of the instantaneous week of the year try:

import datetime
datetime.datetime.utcnow().isocalendar()[1]
Kaki answered 5/2, 2015 at 10:10 Comment(0)
M
12

I found these to be the quickest way to get the week number; all of the variants.

from datetime import datetime


dt = datetime(2021, 1, 3)  # Date is January 3rd 2021 (Sunday), year starts with Friday

dt.strftime("%W")  # '00'; Monday is considered first day of week, Sunday is the last day of the week which started in the previous year
dt.strftime("%U")  # '01'; Sunday is considered first day of week
dt.strftime("%V")  # '53'; ISO week number; result is '53' since there is no Thursday in this year's part of the week

Further clarification for %V can be found in the Python doc:

The ISO year consists of 52 or 53 full weeks, and where a week starts on a Monday and ends on a Sunday. The first week of an ISO year is the first (Gregorian) calendar week of a year containing a Thursday. This is called week number 1, and the ISO year of that Thursday is the same as its Gregorian year.

https://docs.python.org/3/library/datetime.html#datetime.date.isocalendar

NOTE: Bear in mind the return value is a string, so pass the result to a int constructor if you need a number.

Madelinemadella answered 1/7, 2021 at 14:23 Comment(0)
Q
10

If you are only using the isocalendar week number across the board the following should be sufficient:

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

This retrieves the second member of the tuple returned by isocalendar for our week number.

However, if you are going to be using date functions that deal in the Gregorian calendar, isocalendar alone will not work! Take the following example:

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

The string here says to return the Monday of the first week in 2014 as our date. When we use isocalendar to retrieve the week number here, we would expect to get the same week number back, but we don't. Instead we get a week number of 2. Why?

Week 1 in the Gregorian calendar is the first week containing a Monday. Week 1 in the isocalendar is the first week containing a Thursday. The partial week at the beginning of 2014 contains a Thursday, so this is week 1 by the isocalendar, and making date week 2.

If we want to get the Gregorian week, we will need to convert from the isocalendar to the Gregorian. Here is a simple function that does the trick.

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
Quarles answered 17/9, 2015 at 19:13 Comment(0)
L
7

I summarize the discussion to two steps:

  1. Convert the raw format to a datetime object.
  2. Use the function of a datetime object or a date object to calculate the week number.

Warm up

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

1st step

To manually generate a datetime object, we can use datetime.datetime(2017,5,3) or datetime.datetime.now().

But in reality, we usually need to parse an existing string. we can use strptime function, such as datetime.strptime('2017-5-3','%Y-%m-%d') in which you have to specific the format. Detail of different format code can be found in the official documentation.

Alternatively, a more convenient way is to use dateparse module. Examples are dateparser.parse('16 Jun 2010'), dateparser.parse('12/2/12') or dateparser.parse('2017-5-3')

The above two approaches will return a datetime object.

2nd step

Use the obtained datetime object to call strptime(format). For example,

python

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.

It's very tricky to decide which format to use. A better way is to get a date object to call isocalendar(). For example,

python

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

In reality, you will be more likely to use date.isocalendar() to prepare a weekly report, especially in the Christmas-New Year shopping season.

Ldopa answered 4/5, 2017 at 2:46 Comment(0)
K
6

You can try %W directive as below:

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

'%W': Week number of the year (Monday as the first day of the week) as a decimal number. All days in a new year preceding the first Monday are considered to be in week 0. (00, 01, ..., 53)

Kendry answered 31/5, 2016 at 4:39 Comment(0)
I
5

For pandas users, if you want to get a column of week number:

df['weekofyear'] = df['Date'].dt.week
Indorse answered 19/11, 2021 at 3:17 Comment(0)
C
3

This week:

import datetime as dt
dt.date.today().isocalendar().week

For any other week, substitute today() with date(year, month, day).

Have a nice week.

Colima answered 19/12, 2023 at 8:13 Comment(0)
S
2

isocalendar() returns incorrect year and weeknumber values for some dates:

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

Compare with Mark Ransom's approach:

>>> 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
Shandrashandrydan answered 15/4, 2014 at 16:58 Comment(1)
Looking at some links about the iso8601 calendar (e.g., staff.science.uu.nl/~gent0113/calendar/isocalendar.htm), I see that the year and weeknumber values returned by isocalendar() are not "incorrect" as such. Under ISO8601, for example, the year 2004 started on December 29, 2003. So isocalendar() may be correct in returning a year of 2015 for Dec.29 2014, but for a lot of people's purposes, this is going to be pretty misleading.Shandrashandrydan
M
2

Let's say you need to have a week combined with the year of the current day as a string.

import datetime
year,week = datetime.date.today().isocalendar()[:2]
week_of_the_year = f"{year}-{week}"
print(week_of_the_year)

You might get something like 2021-28

Meed answered 15/7, 2021 at 14:30 Comment(0)
S
1

If you want to change the first day of the week you can make use of the calendar module.

import calendar
import datetime

calendar.setfirstweekday(calendar.WEDNESDAY)
isodate = datetime.datetime.strptime(sweek,"%Y-%m-%d").isocalendar()
week_of_year = isodate[1]

For example, calculate the sprint number for a week starting on WEDNESDAY:

def calculate_sprint(sweek):
    calendar.setfirstweekday(calendar.WEDNESDAY)
    isodate=datetime.datetime.strptime(sweek,"%Y-%m-%d").isocalendar()
    return "{year}-{month}".format(year=isodate[0], month=isodate[1])

calculate_sprint('2021-01-01')
>>>'2020-53'
Sundin answered 4/5, 2021 at 21:4 Comment(0)
L
1

We have a similar issue and we came up with this logic I have tested for 1year test cases & all passed

import datetime


def week_of_month(dt):

    first_day = dt.replace(day=1)
    dom = dt.day
    if first_day.weekday() == 6:
        adjusted_dom = dom
    else:
        adjusted_dom = dom + first_day.weekday()
    if adjusted_dom % 7 == 0 and first_day.weekday() != 6:
       value = adjusted_dom / 7.0 + 1
    elif first_day.weekday() == 6 and adjusted_dom % 7 == 0 and adjusted_dom == 7:
        value = 1
    else:
        value = int(ceil(adjusted_dom / 7.0))

    return int(value)


year = 2020
month = 01
date = 01

date_value = datetime.datetime(year, month, date).date()
no = week_of_month(date_value)
Lanitalank answered 18/5, 2021 at 6:23 Comment(0)
S
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.............!!!") 
Selfsacrifice answered 20/9, 2015 at 16:59 Comment(0)
M
-2

A lot of answers have been given, but id like to add to them.

If you need the week to display as a year/week style (ex. 1953 - week 53 of 2019, 2001 - week 1 of 2020 etc.), you can do this:

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)

It will take the current year and week, and long_week_num in the day of writing this will be:

>>> 2006
Mathematical answered 6/2, 2020 at 11:30 Comment(2)
Why create a date() from scratch? datetime.datetime() instances have a .date() method for that job.Faxan
However, more worryingly is that your answer picks the century, not the current year. And if you are going to use string formatting for the week number, why then not also use that to include the year?Faxan

© 2022 - 2024 — McMap. All rights reserved.