3

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.

Community
  • 1
  • 1
Jeremy Jones
  • 4,561
  • 3
  • 16
  • 26
  • Duplicate of http://stackoverflow.com/a/7687085/5324657, but that handy isoweek module isn't built-in. Is there a built-in way to do this? – Jeremy Jones Dec 05 '16 at 14:53
  • 1
    That duplicate question gives the only built-in ways to do it too; if your definition of week doesn't match Python's (and you can't use Python 3.6's ISO friendly `strptime`), then no, there is no (moderately clean) built-in way. Wanting there to be a built-in doesn't make it so. – ShadowRanger Dec 05 '16 at 15:38

1 Answers1

0

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