154

Please what's wrong with my code:

import datetime
d = "2013-W26"
r = datetime.datetime.strptime(d, "%Y-W%W")
print(r)

Display "2013-01-01 00:00:00", Thanks.

Ali SAID OMAR
  • 6,404
  • 8
  • 39
  • 56

8 Answers8

275

A week number is not enough to generate a date; you need a day of the week as well. Add a default:

import datetime
d = "2013-W26"
r = datetime.datetime.strptime(d + '-1', "%Y-W%W-%w")
print(r)

The -1 and -%w pattern tells the parser to pick the Monday in that week. This outputs:

2013-07-01 00:00:00

%W uses Monday as the first day of the week. While you can pick your own weekday, you may get unexpected results if you deviate from that.

See the strftime() and strptime() behaviour section in the documentation, footnote 4:

When used with the strptime() method, %U and %W are only used in calculations when the day of the week and the year are specified.

Note, if your week number is a ISO week date, you'll want to use %G-W%V-%u instead! Those directives require Python 3.6 or newer.

Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
  • 2
    Does not work. datetime.datetime.strptime("2018-W0-0", "%Y-W%W-%w") == datetime.datetime.strptime("2018-W1-0", "%Y-W%W-%w") --> "2018-01-07 00:00:00". 1st and 2nd week of 2018 have the same start date. – ozw1z5rd May 09 '18 at 08:42
  • 2
    @ozw1z5rd: that’s because there is no week 0 in 2018. Week 0 is the partial week before the first Monday of the year; in 2018 the first Monday is the 1st of January. In other words, *your input string* is the problem here, not the technique, and Python has error-corrected to interpret W0 to mean W1 instead. – Martijn Pieters May 09 '18 at 09:27
  • @ozw1z5rd: If this is an issue for your app, you’ll need to special-case such years; `if d.endswith('-W0') and r.day == 7: raise ValueError('Invalid date string, No week 0 in {}'.format(r.year))` – Martijn Pieters May 09 '18 at 09:31
  • Any idea how to deal with non zero padded week numbers? (e.g. 2020-w1, 2020-w52) – Michael H. Dec 29 '20 at 11:19
  • 1
    @MichaelH.: I'm not sure what you are asking. – Martijn Pieters Jan 04 '21 at 10:23
  • Watch out if you're using ISO weeks! You'll need to use a different parse string as indicated at the bottom of the answer. Took me a while to figure this out. – Cornelius Roemer Mar 29 '21 at 11:11
  • @CorneliusRoemer: they are at the bottom because the question uses the non-ISO patterns. – Martijn Pieters Mar 30 '21 at 11:37
47

In Python 3.8 there is the handy datetime.date.fromisocalendar:

>>> from datetime import date
>>> date.fromisocalendar(2020, 1, 1)  # (year, week, day of week)
datetime.date(2019, 12, 30, 0, 0)

In older Python versions (3.7-) the calculation can use the information from datetime.date.isocalendar to figure out the week ISO8601 compliant weeks:

from datetime import date, timedelta

def monday_of_calenderweek(year, week):
    first = date(year, 1, 1)
    base = 1 if first.isocalendar()[1] == 1 else 8
    return first + timedelta(days=base - first.isocalendar()[2] + 7 * (week - 1))

Both works also with datetime.datetime.

Jens W. Klein
  • 731
  • 5
  • 7
39

To complete the other answers - if you are using ISO week numbers, this string is appropriate (to get the Monday of a given ISO week number):

import datetime
d = '2013-W26'
r = datetime.datetime.strptime(d + '-1', '%G-W%V-%u')
print(r)

%G, %V, %u are ISO equivalents of %Y, %W, %w, so this outputs:

2013-06-24 00:00:00

Availabe in Python 3.6+; from docs.

Luka Kikelj
  • 491
  • 4
  • 5
7
import datetime
res = datetime.datetime.strptime("2018 W30 w1", "%Y %W w%w")
print res

Adding of 1 as week day will yield exact current week start. Adding of timedelta(days=6) will gives you the week end.

datetime.datetime(2018, 7, 23)
3

If anyone is looking for a simple function that returns all working days (Mo-Fr) dates from a week number consider this (based on accepted answer)

import datetime

def weeknum_to_dates(weeknum):
    return [datetime.datetime.strptime("2021-W"+ str(weeknum) + str(x), "%Y-W%W-%w").strftime('%d.%m.%Y') for x in range(-5,0)]

weeknum_to_dates(37)

Output:

['17.09.2021', '16.09.2021', '15.09.2021', '14.09.2021', '13.09.2021']
do-me
  • 1,600
  • 1
  • 10
  • 16
1

In case you have the yearly number of week, just add the number of weeks to the first day of the year.

>>> import datetime
>>> from dateutil.relativedelta import relativedelta

>>> week = 40
>>> year = 2019
>>> date = datetime.date(year,1,1)+relativedelta(weeks=+week)
>>> date
datetime.date(2019, 10, 8)
dimosbele
  • 381
  • 3
  • 19
1

Another solution which worked for me that accepts series data as opposed to strptime only accepting single string values:

#fw_to_date
import datetime
import pandas as pd

# fw is input in format 'YYYY-WW'
# Add weekday number to string 1 = Monday
fw = fw + '-1'
# dt is output column 
# Use %G-%V-%w if input is in ISO format
dt = pd.to_datetime(fw, format='%Y-%W-%w', errors='coerce')
igeis
  • 31
  • 5
0

Here's a handy function including the issue with zero-week.

Ron
  • 22,128
  • 31
  • 108
  • 206