53

Possible Duplicate:
What’s the best way to find the inverse of datetime.isocalendar()?

I have an ISO 8601 year and week number, and I need to translate this to the date of the first day in that week (Monday). How can I do this?

datetime.strptime() takes both a %W and a %U directive, but neither adheres to the ISO 8601 weekday rules that datetime.isocalendar() use.

Update: Python 3.6 supports the %G, %V and %u directives also present in libc, allowing this one-liner:

>>> from datetime import datetime
>>> datetime.strptime('2011 22 1', '%G %V %u')
datetime.datetime(2011, 5, 30, 0, 0)

Update 2: Python 3.8 added the fromisocalendar() method, which is even more intuitive:

>>> from datetime import datetime
>>> datetime.fromisocalendar(2011, 22, 1)
datetime.datetime(2011, 5, 30, 0, 0)
Erik Cederstrand
  • 9,643
  • 8
  • 39
  • 63
  • 4
    Why not elegant? The other options you'll find through google are even more ugly. –  May 04 '11 at 11:10
  • 3
    I found a related question with a nice answer: http://stackoverflow.com/questions/304256/whats-the-best-way-to-find-the-inverse-of-datetime-isocalendar – Erik Cederstrand May 04 '11 at 11:55
  • I see mention of a %V directive in PHP strftime() and also libc strptime() but apparently Python doesn't implement it. I went with the solution in the link I posted above. – Erik Cederstrand May 05 '11 at 09:36
  • @ErikCederstrand: Thank you for your post! I am using Python 3.8.8 but when I tried running `datetime.fromisocalendar(2011, 22, 1)`, I got the following error message: `AttributeError: module 'datetime' has no attribute 'fromisocalendar'`. I ran `pip install datetime` and it appears that it installed version 4.7. Do you know what could be causing the issue? – Leonidas Dec 05 '22 at 16:31
  • Figured it out! I had to put `datetime.datetime.fromisocalendar(2011, 22, 1)`. – Leonidas Dec 05 '22 at 16:38
  • The `datetime` module referenced above is the one from the standard library (https://docs.python.org/3/library/datetime.html), not https://pypi.org/project/DateTime/ – Erik Cederstrand Dec 05 '22 at 20:56

2 Answers2

76

With the isoweek module you can do it with:

from isoweek import Week
d = Week(2011, 40).monday()
gisle
  • 761
  • 1
  • 5
  • 2
  • This is definitely the most practical way to go, especially if you are doing a lot of manipulation of ISO weeks. – gldnspud Feb 10 '15 at 15:25
  • SInce Python 3.8, the original question can be answered easily without dependencies for a given datetime object: `current_iso_day_number = datetime_obj.isocalendar()[2]; return datetime_obj.replace(days=(current_iso_day_number - 1))`. This subtracts enough days to get the `datetime` object to ISO weekday 1. (I had to answer here since the question is closed.) – arcanemachine Jul 08 '22 at 10:23
37

%W takes the first Monday to be in week 1 but ISO defines week 1 to contain 4 January. So the result from

datetime.strptime('2011221', '%Y%W%w')

is off by one iff the first Monday and 4 January are in different weeks. The latter is the case if 4 January is a Friday, Saturday or Sunday. So the following should work:

from datetime import datetime, timedelta, date
def tofirstdayinisoweek(year, week):
    ret = datetime.strptime('%04d-%02d-1' % (year, week), '%Y-%W-%w')
    if date(year, 1, 4).isoweekday() > 4:
        ret -= timedelta(days=7)
    return ret
Uwe Kleine-König
  • 3,426
  • 1
  • 24
  • 20