Search code examples
pythondatetimedayofweekweek-number

In Python how can I get a date based on a year, week number & weekday?


Given a date value and a number, I want to see how that number compares to the one for the equivalent day on preceding years.

For 'equivalent day', I mean the same week number and the same weekday, NOT the same calendar date.

For example, starting with a date like 25 May 1975:

>>> holyGrail = datetime.datetime(1975,5,25)

which is the seventh day of the 21st week:

>>> holyGrail.isocalendar()
(1975, 21, 7)
>>>

I want to pull up the dates of the 7th day of the 21st week for 1974, 1973 etc..

Essentially I want to do something like this:

>>> yearBack = datetime.datetime().isocalendar(1974,21,7)

and have it return me the date matching that week & weekday, which in this case would be the 26th May 1974, not the 25th:

>>> yearBack = datetime.datetime(1974,5,26)
>>> yearBack.isocalendar()
(1974, 21, 7)
>>>

I see from https://stackoverflow.com/a/28069361/5324657 that there is an (undocumented?) format %V to strftime(), returning the ISO-8601 week number, which works ok in strftime and seems to be what I need, however when I try to use the same %V format in strptime() I get the error

ValueError: 'V' is a bad directive in format '%Y-%V-%w'

How can I easily/reliably pull up equivalent Year/WeekNo/Weekday dates going back in time?

Note that I don't really care about when weeks start or what constitutes a full week over New Year, I just need a consistent method which will allow for accurate year-on-year comparisons.


Solution

  • I think this should work:

    def getDate(d, y):
        s = datetime.date(y, 1, 1)
        while s.isocalendar()[2] != 4:
            s += datetime.timedelta(days=1)
        s += datetime.timedelta(weeks=d.isocalendar()[1]-1,
                                days=d.isocalendar()[2]-s.isocalendar()[2])
        if d.isocalendar()[-2:] == s.isocalendar()[-2:]:
             return s
        raise ValueError("{} has no equivalent in {}".format(d, y))
    

    In the Gregorian calendar, some years have 52 weeks and some have 53, so there is not always an equivalent date. It will raise ValueError in those instances.

    >>>print(getDate(datetime.date(1975, 5, 25), 1974))
    1974-05-26
    
    >>>print(getDate(datetime.date(1975, 5, 25), 1973))
    1973-05-27
    
    >>>print(getDate(datetime.date(1975, 5, 25), 1972))
    1972-05-28
    
    >>>print(getDate(datetime.date(1904, 1, 03), 1978))
    ValueError: 1904-01-03 has no equivalent in 1978