58

I'm trying to calculate the difference between two dates in "weeks of year". I can get the datetime object and get the days etc but not week numbers. I can't, of course, subtract dates because weekends can't be ensured with that.

I tried getting the week number using d1.isocalendar()[1] and subtracting d2.isocalendar()[1] but the issue is that isocalendar()[1] returns December 31, 2012 as week 1 (which supposedly is correct) but that means my logic cannot span over this date.

For reference, here's my complete code:

def week_no(self):
    ents = self.course.courselogentry_set.all().order_by('lecture_date')
    l_no = 1
    for e in ents:
        if l_no == 1: 
             starting_week_of_year = e.lecture_date.isocalendar()[1] # get week of year
             initial_year = e.lecture_date.year   
        if e == self: 
            this_year = e.lecture_date.year
            offset_week = (this_year - initial_year) * 52
            w_no = e.lecture_date.isocalendar()[1] - starting_week_of_year + 1 + offset_week
            break 
        l_no += 1
    return w_no  

With this code, the lecture on Dec 31, 2012 ends up being -35.

recluze
  • 1,920
  • 4
  • 21
  • 34

7 Answers7

83

How about calculating the difference in weeks between the Mondays within weeks of respective dates? In the following code, monday1 is the Monday on or before d1 (the same week):

from datetime import datetime, timedelta

monday1 = (d1 - timedelta(days=d1.weekday()))
monday2 = (d2 - timedelta(days=d2.weekday()))

print 'Weeks:', (monday2 - monday1).days / 7

Returns 0 if both dates fall withing one week, 1 if on two consecutive weeks, etc.

garyrob
  • 568
  • 7
  • 17
eumiro
  • 207,213
  • 34
  • 299
  • 261
  • 2
    Can you just elaborate your code by explaining it, specially on the `monday1` and `monday2` calculations. – Arup Rakshit Jan 07 '13 at 07:56
  • 1
    Works perfectly, spans across years and weeks. Very concise too. Thanks a lot :) – recluze Jan 07 '13 at 08:05
  • I get an error with `days()` : `(Pdb) (monday2 - monday1).days() *** TypeError: 'int' object is not callable (Pdb) (monday2 - monday1).days 77` – otmezger May 03 '13 at 19:30
  • Guess I'm a bit late here.. Shouldn't the last line be: print (monday2 - monday1).days/7 instead of print (monday2 - monday1).days()/7 – Saurabh Verma Apr 04 '14 at 18:43
  • Agreed, `timedelta.days` as an attribute, not a method. Unlike `total_seconds()` which is a method. – kendlete Nov 27 '14 at 12:03
  • As far as I can tell, this answer is simply WRONG, because timedelta.days is an attribute rather than a method. Why is it the accepted answer? – garyrob Jul 22 '15 at 14:58
  • 1
    I just edited the answer so that "days" is used instead of "days()". So the last few comments will no longer be relevant (assuming the edit is accepted). I added 'Weeks:' only because edits have to change at least 6 characters. – garyrob Jul 22 '15 at 15:10
  • Suppose, we have 3 epochs ```s = 1326777816; s1 = 1431480091; s2 = 1431434968```. Actually, ```s1``` and ```s2``` are in the same week but using the function above there are 172 weeks between ```s1``` and ```s``` while 173 weeks between ```s2``` and ```s```. It is very strange because ```s2 < s1``` so the number of week should be smaller. Noted: I convert epoch to ```datetime ``` by ```datetime.fromtimestamp(s)``` before applying the function. I think the answer of [Rashmi](http://stackoverflow.com/a/14191912/3138459) is more correct. – tndoan Apr 05 '16 at 03:02
  • This answer is not correct, what to do with both monday's hours, minutes, etc? To get the correct answer the both dates should have hours and minutes and seconds to be reset to zero, otherwise will get negative values in some cases – annndrey Sep 08 '17 at 09:04
  • It is not necessary and distracting to zero d1 and d2 back their previous Mondays at midnight. (d2 - d1).days/7 is all that is needed. Integer division by the 7 means that decimal weeks are chopped off - whala - you get only what you wanted the whole weeks. – small mammal May 03 '18 at 03:05
  • In my opinion it shoud be: (monday2.date() - monday1.date()).days / 7 instead of (monday2 - monday1).days / 7. This gives good result (1 instead of 0) for these two dates: 1970-01-18 15:12:28 1970-01-19 05:05:48 – Cob Nov 15 '18 at 14:22
  • If I'm reading this correctly, d1 and d2 are the two dates, right? What format should the dates be in? – owcs Feb 08 '21 at 19:54
  • Same thing but a bit more concise: `weeks = ((d2 - d1).days + d1.weekday() - d2.weekday()) // 7` – coldfix Jan 07 '22 at 22:16
46

You may want to refer the Python CookBook (2005 edition) Recipe 3.3. The following code snippet is from the cookbook, does what you require.

from dateutil import rrule
import datetime
def weeks_between(start_date, end_date):
    weeks = rrule.rrule(rrule.WEEKLY, dtstart=start_date, until=end_date)
    return weeks.count()
Rashmi Nagaraja
  • 801
  • 11
  • 20
  • Thanks. Haven't tested this out but even it works, I think eumiro's solution is more elegant. +1 though for an alternative :) – recluze Jan 07 '13 at 08:08
28

This is a very simple solution with less coding everyone would understand.

from datetime import date

d1 = date(year, month, day)
d2 = date(year, month, day)
result = (d1-d2).days//7
Transformer
  • 3,642
  • 1
  • 22
  • 33
  • Works tested (date(2018, 5, 3) - date(2017, 12, 25)).days/7 and verified https://www.timeanddate.com/date/durationresult.html?d1=25&m1=12&y1=2017&d2=3&m2=5&y2=2018 – small mammal May 03 '18 at 03:00
  • 1
    Good, it works for you, should be this (date(2018, 5, 3) - date(2017, 12, 25)).days//7 – Transformer May 06 '18 at 19:00
  • 1
    Nice. I missed the floor division. The floor operator is better! I was relying on python 2's default integer division which behaves the same as // but that is not true in python 3. https://stackoverflow.com/questions/183853/in-python-2-what-is-the-difference-between-and-when-used-for-division – small mammal May 06 '18 at 20:27
  • 3
    This solution doesn't give the difference in calendar weeks. For example, if d1 is a Friday and d2 is Tuesday of the following week, there are 4 days between the two dates which would result in 0 weeks but the answer should be 1 calendar week. – Victor Deplasse Jan 06 '21 at 16:13
4

The solution above has a bug (I can't add a comment due to low reputation). It doesn't account for hour differences.

# This code has a bug.
monday1 = (d1 - timedelta(days=d1.weekday()))
monday2 = (d2 - timedelta(days=d2.weekday()))

Counter example of 2 dates more than a week apart:

Timestamp1: 1490208193270795 (22 Mar 2017 18:43:13 GMT)
Monday1: 20 Mar 2017 18:43:13 GMT

Timestamp2: 1489528488744290 (14 Mar 2017 21:54:48 GMT)
Monday2: 13 Mar 2017 21:54:48 GMT

Using that code it returns 0 as week diff when it should be 1. Need to zero out the hours/minutes/seconds as well.

sbilkoloft
  • 41
  • 2
2

To determine how many weeks are spanned by two dates. eg From 3rd Oct to 13th Oct

    October 2015
Mo     5 12 19 26
Tu     6 13 20 27
We     7 14 21 28
Th  1  8 15 22 29
Fr  2  9 16 23 30
Sa  3 10 17 24 31
Su  4 11 18 25

Code:

    import math, datetime

    start_date = datetime.date(2015, 10, 3)
    start_date_monday = (start_date - datetime.timedelta(days=start_date.weekday()))
    end_date = datetime.date(2015, 10, 13)
    num_of_weeks = math.ceil((end_date - start_date_monday).days / 7.0)

Equals 3 weeks.

Neil
  • 8,925
  • 10
  • 44
  • 49
1

Edited Best Answer

from datetime import timedelta
monday1 = (d1 - timedelta(days=d1.weekday()))
monday2 = (d2 - timedelta(days=d2.weekday()))
diff = monday2 - monday1
noWeeks = (diff.days / 7)  + math.ceil(diff.seconds/86400)
print('Weeks:', noWeeks)`
  • Could you please elaborate your answer and what is the improvement? – Suthiro Dec 03 '20 at 06:27
  • Please don't post only code as answer, but also provide an explanation what your code does and how it solves the problem of the question. Answers with an explanation are usually more helpful and of better quality, and are more likely to attract upvotes – Pouria Hemi Dec 03 '20 at 07:03
0

You're a bit vague on what 'difference in weeks' means exactly. Is 6 days difference one week or zero ? Is eight days difference one week or two ?

In any case, why can't you simply find the difference in another unit (seconds or days) and divide by the appropriate amount, with your prefered rounding for weeks?

Thomas Vander Stichele
  • 36,043
  • 14
  • 56
  • 60
  • Thanks for the input. I was actually talking about difference in "week of year". So, it's not sufficient to say "6 days". If first day is monday, second is thursday, week difference is 0 but if one is saturday and two is sunday, week difference is 1. – recluze Jan 07 '13 at 08:07