1
from datetime import datetime
from dateutil import relativedelta
date1 = datetime.strptime(str('2011-08-15 12:00:00'), '%Y-%m-%d %H:%M:%S')
date2 = datetime.strptime(str('2012-02-15'), '%Y-%m-%d')
r = relativedelta.relativedelta(date2, date1)
r.months

The code above does the trick for me but i don't want to import dateutil. Does anyone have an example for me without looping?

I want to deduct two dates from each other and i want to know the difference in months between the two dates in whole months.

2 Answers2

1

Seems this post helps: How do I find the time difference between two datetime objects in python?

simply do a substraction on two datetime obj, then you can get what detail you want in the diff.

Community
  • 1
  • 1
vivi
  • 334
  • 2
  • 13
0

Interestingly enough, your code outputs to: 5 which means, as suggested in the comments, that you are probably interested in the duration of each month and you do not want to round your results. Unfortunately the timedelta object will not work for you in this case because by definition, a time difference does not hold the information you need to obtain the duration of the months of interest to you.

You should probably take a look here: Python: Difference of 2 datetimes in months where they discuss a solution using calendar instead of dateutil.

Otherwise, if you are happy with an approximated (and rounded) estimate, you could go close enough by doing:

DAYS_PER_MONTH = 30  # or 365.0 / 12.0 for more precision
datetime_diff = date2 - date1
print(datetime_diff.days / DAYS_PER_MONTH)  # '//' for floored result

If you want to get back to some code that works with your data (but not with all data, because of e.g. leap years, leap seconds, etc.) have a look here:

MONTH_NUM_DAYS = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
YEAR_LENGTH = 365.25  # average year duration, including leap years

def num_days_in_months(
        begin_month, end_month, month_duration=MONTH_NUM_DAYS):
    begin_month, end_month = sorted((begin_month, end_month))
    return sum(month_duration[begin_month:end_month])

def get_num_months(begin_date, end_date, num_days_per_year=YEAR_LENGTH):
    begin_month = begin_date.month
    end_month = end_date.month
    month_diff = abs(end_month - begin_month)
    num_days = (end_date - begin_date).days
    num_days_within_year = num_days % num_days_per_year
    num_months = num_days // num_days_per_year
    num_days_max = num_days_in_months(begin_month, end_month)
    print(num_months, month_diff)
    if num_days_within_year < num_days_max:
        num_months += month_diff - 1
    else:
        num_months += month_diff
    return num_months
Community
  • 1
  • 1
norok2
  • 25,683
  • 4
  • 73
  • 99
  • It's 5 months because the delta is actually 5 mos, 30.5 days. The time in the first day is 12:00, in the second one it is implicitly 0:00. You would get 6 mos if the times were the same (either omit the first time or set the second one to 12:00, for example) – Mad Physicist Jul 29 '16 at 14:18
  • I see.. I obviously overlooked that the expected behavior was not `round(num_months)`, but rather `floor(num_months)`, and you are interested in the exact duration of each month, in which case the `timedelta` object is not an option there, so there is probably not a solution that does not involve cycling through the duration of each month – norok2 Jul 29 '16 at 16:06
  • I assumed you knew about the floor operation because that is what you do with `//` in your answer too. – Mad Physicist Jul 29 '16 at 16:08
  • Thanks, I have edited the answer to reflect your suggestions. – norok2 Jul 29 '16 at 16:21
  • @norok2 could you give exaqmple dates with your code please? – Alban Barbosa Aug 01 '16 at 09:44
  • The code above will not work if you want to get `5`, because the `datetime_diff` will have no information about the start and end dates. The time difference is _on average_ 6 months and that is what you will get with an _average_ definition of month. If need something that works on your scenario, you have to do something different, and would probably involve a (more or less hidden) loop... probably your best shot is just to copy the code from `dateutils` if you want your result to be robust enough... – norok2 Aug 01 '16 at 11:26
  • I have actually edited the code so that there is some code that does the trick but should not be 100% robust, as there is no proper support for leap years, leap seconds, etc., but it works a relatively large number of situations. – norok2 Aug 02 '16 at 08:30