user6083088
user6083088

Reputation: 1037

Calculate year week number subtracting week number in Python

I'm trying to find a custom date format like YYYYW eg. 201620 after subtracting a number of week periods.

So far I've been able to convert a date string like YYYYW into date using the following code;

from datetime import datetime

myDate = "201642"
year = myDate[:4]
week = myDate[-2:]
day = '1'
myDate = year + " " + week + " " + day
print(myDate)
date = datetime.strptime(myDate, "%Y %W %w")
print(date)

But I'm unable to find a way where I can subtract for eg. 43 weeks from 201642 and get a result like 201552.

EDIT 1: Using suggestions from the comments, here is the solution.

from datetime import datetime from datetime import timedelta

myDate = "201642"
year = myDate[:4]
week = myDate[-2:]
day = '1'
myDate = year + " " + week + " " + day
print(myDate)
date = datetime.strptime(myDate, "%Y %W %w")
print(date)
new_date = date - timedelta(weeks=42)
str_new_date = datetime.strftime(new_date, '%Y%W')
print(str_new_date)

Upvotes: 3

Views: 2905

Answers (3)

Harvey
Harvey

Reputation: 5821

Other than doing the math yourself, here's an attempt using datetime. Doing everything using ISO week numbers (using methods from this answer):

>>> import datetime
>>> date = '201642'
>>> weeks = 43
>>> year = date[:4]
>>> week = date[4:]

>>> start = iso_to_gregorian(int(year), int(week), 1)
>>> start
datetime.date(2016, 10, 17)
>>> start.isocalendar()
(2016, 42, 1)
>>> offset_weeks = datetime.timedelta(weeks=43)
>>> end = start - offset_weeks
>>> end
datetime.date(2015, 12, 21)
>>> end.isocalendar()
(2015, 52, 1)
>>> '{}{}'.format(*end.isocalendar())
'201552'

A modified version of @Hildy's answer below:

In [29]: start = datetime.datetime.strptime(date + '0', '%Y%W%w')

In [30]: start
Out[30]: datetime.datetime(2016, 10, 23, 0, 0)

In [31]: start.strftime('%Y%W')
Out[31]: '201642'

In [32]: end = start - datetime.timedelta(weeks=43)

In [33]: end
Out[33]: datetime.datetime(2015, 12, 27, 0, 0)

In [34]: end.strftime('%Y%W')
Out[34]: '201551'

Upvotes: 2

Hildy
Hildy

Reputation: 510

This can be done with relative delta, from the dateutil library; it should be noted that said library is part of the standard lib in Python 2x, but not 3x...you'll have to install it.

The next thing you need to know is that, per the Python docs, "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."

Try this out:

from dateutil.relativedelta import relativedelta
from datetime import datetime

#I've added the day number here, as described in the docs
myDate = "2016042"
# with '%w' added, strptime() will work
date = datetime.strptime(myDate, "%Y%w%W")
# now use relativedelta() to do the date math
date = date - relativedelta(weeks=2)
# finally, use strftime() to return the date back to the format you like
myDate = date.strftime("%Y%W")

print(string_date)

I've used this in ETL operations to calculate things like fiscal periods and it works great. As noted by others here, timedelta() can be used in a similar fashion.

Upvotes: 2

abarnert
abarnert

Reputation: 366083

You haven't actually parsed the date properly in your sample code, but since you say your actual code does, let's ignore that.

So, you have a datetime object. You want to subtract 43 weeks from that. All you have to do is… exactly that, using a timedelta:

>>> dt = datetime.datetime(2016, 10, 21)
>>> dt - datetime.timedelta(weeks=43)
datetime.datetime(2015, 12, 25, 0, 0)

The result is the same time, same day of the week, 43 weeks earlier.


But it's worth noting that, for local times, that "same time" could be off by an hour because of crossing a daylight saving border. And being off by an hour can be especially confusing when you're using midnight. So it's usually better to use date objects instead of datetime objects for this kind of work:

>>> dt = datetime.datetime(2016, 10, 21)
>>> dt.date()
datetime.date(2016, 10, 21)
>>> dt.date() - datetime.timedelta(weeks=43)
datetime.date(2015, 12, 25)

Either way, if you want to turn that back into a YYYYWW string, both datetime and date have strftime methods for that:

>>> d2 = dt - datetime.timedelta(weeks=43)
>>> d2.strftime('%Y%W')
'201551'

Upvotes: 2

Related Questions