Best way to find the months between two dates

PythonDatetimeMonthcalendarDate Math

Python Problem Overview


I have the need to be able to accurately find the months between two dates in python. I have a solution that works but its not very good (as in elegant) or fast.

dateRange = [datetime.strptime(dateRanges[0], "%Y-%m-%d"), datetime.strptime(dateRanges[1], "%Y-%m-%d")]
months = [] 
    
tmpTime = dateRange[0]
oneWeek = timedelta(weeks=1)
tmpTime = tmpTime.replace(day=1)
dateRange[0] = tmpTime
dateRange[1] = dateRange[1].replace(day=1)
lastMonth = tmpTime.month
months.append(tmpTime)
while tmpTime < dateRange[1]:
    if lastMonth != 12:
        while tmpTime.month <= lastMonth:
            tmpTime += oneWeek
        tmpTime = tmpTime.replace(day=1)
        months.append(tmpTime)
        lastMonth = tmpTime.month
            
    else:
        while tmpTime.month >= lastMonth:
            tmpTime += oneWeek
        tmpTime = tmpTime.replace(day=1)
        months.append(tmpTime)
        lastMonth = tmpTime.month

So just to explain, what I'm doing here is taking the two dates and converting them from iso format into python datetime objects. Then I loop through adding a week to the start datetime object and check if the numerical value of the month is greater (unless the month is December then it checks if the date is less), If the value is greater I append it to the list of months and keep looping through until I get to my end date.

It works perfectly it just doesn't seem like a good way of doing it...

Python Solutions


Solution 1 - Python

Start by defining some test cases, then you will see that the function is very simple and needs no loops

from datetime import datetime

def diff_month(d1, d2):
    return (d1.year - d2.year) * 12 + d1.month - d2.month

assert diff_month(datetime(2010,10,1), datetime(2010,9,1)) == 1
assert diff_month(datetime(2010,10,1), datetime(2009,10,1)) == 12
assert diff_month(datetime(2010,10,1), datetime(2009,11,1)) == 11
assert diff_month(datetime(2010,10,1), datetime(2009,8,1)) == 14

You should add some test cases to your question, as there are lots of potential corner cases to cover - there is more than one way to define the number of months between two dates.

Solution 2 - Python

One liner to find a list of datetimes, incremented by month, between two dates.

import datetime
from dateutil.rrule import rrule, MONTHLY

strt_dt = datetime.date(2001,1,1)
end_dt = datetime.date(2005,6,1)

dates = [dt for dt in rrule(MONTHLY, dtstart=strt_dt, until=end_dt)]

Solution 3 - Python

This worked for me -

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

Solution 4 - Python

You can easily calculate this using rrule from dateutil module:

from dateutil import rrule
from datetime import date

print(list(rrule.rrule(rrule.MONTHLY, dtstart=date(2013, 11, 1), until=date(2014, 2, 1))))

will give you:

 [datetime.datetime(2013, 11, 1, 0, 0),
 datetime.datetime(2013, 12, 1, 0, 0),
 datetime.datetime(2014, 1, 1, 0, 0),
 datetime.datetime(2014, 2, 1, 0, 0)]

Solution 5 - Python

from dateutil import relativedelta

r = relativedelta.relativedelta(date1, date2)

months_difference = (r.years * 12) + r.months

Solution 6 - Python

Get the ending month (relative to the year and month of the start month ex: 2011 January = 13 if your start date starts on 2010 Oct) and then generate the datetimes beginning the start month and that end month like so:

dt1, dt2 = dateRange
start_month=dt1.month
end_months=(dt2.year-dt1.year)*12 + dt2.month+1
dates=[datetime.datetime(year=yr, month=mn, day=1) for (yr, mn) in (
          ((m - 1) / 12 + dt1.year, (m - 1) % 12 + 1) for m in range(start_month, end_months)
      )]

if both dates are on the same year, it could also be simply written as:

dates=[datetime.datetime(year=dt1.year, month=mn, day=1) for mn in range(dt1.month, dt2.month + 1)]

Solution 7 - Python

This post nails it! Use dateutil.relativedelta.

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

Solution 8 - Python

My simple solution:

import datetime

def months(d1, d2):
    return d1.month - d2.month + 12*(d1.year - d2.year)

d1 = datetime.datetime(2009, 9, 26)  
d2 = datetime.datetime(2019, 9, 26) 

print(months(d1, d2))

Solution 9 - Python

Define a "month" as 1/12 year, then do this:

def month_diff(d1, d2): 
    """Return the number of months between d1 and d2, 
    such that d2 + month_diff(d1, d2) == d1
    """
    diff = (12 * d1.year + d1.month) - (12 * d2.year + d2.month)
    return diff

You might try to define a month as "a period of either 29, 28, 30 or 31 days (depending on the year)". But you you do that, you have an additional problem to solve.

While it's usually clear that June 15th + 1 month should be July 15th, it's not usually not clear if January 30th + 1 month is in February or March. In the latter case, you may be compelled to compute the date as February 30th, then "correct" it to March 2nd. But when you do that, you'll find that March 2nd - 1 month is clearly February 2nd. Ergo, reductio ad absurdum (this operation is not well defined).

Solution 10 - Python

Update 2018-04-20: it seems that OP @Joshkunz was asking for finding which months are between two dates, instead of "how many months" are between two dates. So I am not sure why @JohnLaRooy is upvoted for more than 100 times. @Joshkunz indicated in the comment under the original question he wanted the actual dates [or the months], instead of finding the total number of months.

So it appeared the question wanted, for between two dates 2018-04-11 to 2018-06-01

Apr 2018, May 2018, June 2018 

And what if it is between 2014-04-11 to 2018-06-01? Then the answer would be

Apr 2014, May 2014, ..., Dec 2014, Jan 2015, ..., Jan 2018, ..., June 2018

So that's why I had the following pseudo code many years ago. It merely suggested using the two months as end points and loop through them, incrementing by one month at a time. @Joshkunz mentioned he wanted the "months" and he also mentioned he wanted the "dates", without knowing exactly, it was difficult to write the exact code, but the idea is to use one simple loop to loop through the end points, and incrementing one month at a time.

The answer 8 years ago in 2010:

If adding by a week, then it will approximately do work 4.35 times the work as needed. Why not just:

1. get start date in array of integer, set it to i: [2008, 3, 12], 
       and change it to [2008, 3, 1]
2. get end date in array: [2010, 10, 26]
3. add the date to your result by parsing i
       increment the month in i
       if month is >= 13, then set it to 1, and increment the year by 1
   until either the year in i is > year in end_date, 
           or (year in i == year in end_date and month in i > month in end_date)

just pseduo code for now, haven't tested, but i think the idea along the same line will work.

Solution 11 - Python

Here's how to do this with Pandas FWIW:

import pandas as pd
pd.date_range("1990/04/03", "2014/12/31", freq="MS")

DatetimeIndex(['1990-05-01', '1990-06-01', '1990-07-01', '1990-08-01',
               '1990-09-01', '1990-10-01', '1990-11-01', '1990-12-01',
               '1991-01-01', '1991-02-01',
               ...
               '2014-03-01', '2014-04-01', '2014-05-01', '2014-06-01',
               '2014-07-01', '2014-08-01', '2014-09-01', '2014-10-01',
               '2014-11-01', '2014-12-01'],
              dtype='datetime64[ns]', length=296, freq='MS')

Notice it starts with the month after the given start date.

Solution 12 - Python

Many people have already given you good answers to solve this but I have not read any using list comprehension so I give you what I used for a similar use case :


def compute_months(first_date, second_date):
    year1, month1, year2, month2 = map(
        int, 
        (first_date[:4], first_date[5:7], second_date[:4], second_date[5:7])
    )
    
    return [
        '{:0>4}-{:0>2}'.format(year, month)
        for year in range(year1, year2 + 1)
        for month in range(month1 if year == year1 else 1, month2 + 1 if year == year2 else 13)
    ]

>>> first_date = "2016-05"
>>> second_date = "2017-11"
>>> compute_months(first_date, second_date)
['2016-05',
 '2016-06',
 '2016-07',
 '2016-08',
 '2016-09',
 '2016-10',
 '2016-11',
 '2016-12',
 '2017-01',
 '2017-02',
 '2017-03',
 '2017-04',
 '2017-05',
 '2017-06',
 '2017-07',
 '2017-08',
 '2017-09',
 '2017-10',
 '2017-11']

Solution 13 - Python

There is a simple solution based on 360 day years, where all months have 30 days. It fits most use cases where, given two dates, you need to calculate the number of full months plus the remaining days.

from datetime import datetime, timedelta

def months_between(start_date, end_date):
    #Add 1 day to end date to solve different last days of month 
    s1, e1 = start_date , end_date  + timedelta(days=1)
    #Convert to 360 days
    s360 = (s1.year * 12 + s1.month) * 30 + s1.day
    e360 = (e1.year * 12 + e1.month) * 30 + e1.day
    #Count days between the two 360 dates and return tuple (months, days)
    return divmod(e360 - s360, 30)

print "Counting full and half months"
print months_between( datetime(2012, 01, 1), datetime(2012, 03, 31)) #3m
print months_between( datetime(2012, 01, 1), datetime(2012, 03, 15)) #2m 15d
print months_between( datetime(2012, 01, 16), datetime(2012, 03, 31)) #2m 15d
print months_between( datetime(2012, 01, 16), datetime(2012, 03, 15)) #2m
print "Adding +1d and -1d to 31 day month"
print months_between( datetime(2011, 12, 01), datetime(2011, 12, 31)) #1m 0d
print months_between( datetime(2011, 12, 02), datetime(2011, 12, 31)) #-1d => 29d
print months_between( datetime(2011, 12, 01), datetime(2011, 12, 30)) #30d => 1m
print "Adding +1d and -1d to 29 day month"
print months_between( datetime(2012, 02, 01), datetime(2012, 02, 29)) #1m 0d
print months_between( datetime(2012, 02, 02), datetime(2012, 02, 29)) #-1d => 29d
print months_between( datetime(2012, 02, 01), datetime(2012, 02, 28)) #28d
print "Every month has 30 days - 26/M to 5/M+1 always counts 10 days"
print months_between( datetime(2011, 02, 26), datetime(2011, 03, 05))
print months_between( datetime(2012, 02, 26), datetime(2012, 03, 05))
print months_between( datetime(2012, 03, 26), datetime(2012, 04, 05))

Solution 14 - Python

Somewhat a little prettified solution by @Vin-G.

import datetime

def monthrange(start, finish):
  months = (finish.year - start.year) * 12 + finish.month + 1 
  for i in xrange(start.month, months):
    year  = (i - 1) / 12 + start.year 
    month = (i - 1) % 12 + 1
    yield datetime.date(year, month, 1)

Solution 15 - Python

You can also use the arrow library. This is a simple example:

from datetime import datetime
import arrow

start = datetime(2014, 1, 17)
end = datetime(2014, 6, 20)

for d in arrow.Arrow.range('month', start, end):
    print d.month, d.format('MMMM')

This will print:

1 January
2 February
3 March
4 April
5 May
6 June

Hope this helps!

Solution 16 - Python

Try something like this. It presently includes the month if both dates happen to be in the same month.

from datetime import datetime,timedelta

def months_between(start,end):
    months = []
    cursor = start

    while cursor <= end:
        if cursor.month not in months:
            months.append(cursor.month)
        cursor += timedelta(weeks=1)

    return months

Output looks like:

>>> start = datetime.now() - timedelta(days=120)
>>> end = datetime.now()
>>> months_between(start,end)
[6, 7, 8, 9, 10]

Solution 17 - Python

Solution 18 - Python

It can be done using datetime.timedelta, where the number of days for skipping to next month can be obtained by calender.monthrange. monthrange returns weekday (0-6 ~ Mon-Sun) and number of days (28-31) for a given year and month.
For example: monthrange(2017, 1) returns (6,31).

Here is the script using this logic to iterate between two months.

from datetime import timedelta
import datetime as dt
from calendar import monthrange

def month_iterator(start_month, end_month):
    start_month = dt.datetime.strptime(start_month,
                                   '%Y-%m-%d').date().replace(day=1)
    end_month = dt.datetime.strptime(end_month,
                                 '%Y-%m-%d').date().replace(day=1)
    while start_month <= end_month:
        yield start_month
        start_month = start_month + timedelta(days=monthrange(start_month.year, 
                                                         start_month.month)[1])

`

Solution 19 - Python

from datetime import datetime
from dateutil import relativedelta

def get_months(d1, d2):
    date1 = datetime.strptime(str(d1), '%Y-%m-%d')
    date2 = datetime.strptime(str(d2), '%Y-%m-%d')
    print (date2, date1)
    r = relativedelta.relativedelta(date2, date1)
    months = r.months +  12 * r.years
    if r.days > 0:
        months += 1
    print (months)
    return  months


assert  get_months('2018-08-13','2019-06-19') == 11
assert  get_months('2018-01-01','2019-06-19') == 18
assert  get_months('2018-07-20','2019-06-19') == 11
assert  get_months('2018-07-18','2019-06-19') == 12
assert  get_months('2019-03-01','2019-06-19') == 4
assert  get_months('2019-03-20','2019-06-19') == 3
assert  get_months('2019-01-01','2019-06-19') == 6
assert  get_months('2018-09-09','2019-06-19') == 10

Solution 20 - Python

Get difference in number of days, months and years between two dates.

import datetime    
from dateutil.relativedelta import relativedelta


iphead_proc_dt = datetime.datetime.now()
new_date = iphead_proc_dt + relativedelta(months=+25, days=+23)

# Get Number of Days difference bewtween two dates
print((new_date - iphead_proc_dt).days)

difference = relativedelta(new_date, iphead_proc_dt)

# Get Number of Months difference bewtween two dates
print(difference.months + 12 * difference.years)

# Get Number of Years difference bewtween two dates
print(difference.years)

Solution 21 - Python

#This definition gives an array of months between two dates.
import datetime
def MonthsBetweenDates(BeginDate, EndDate):
    firstyearmonths = [mn for mn in range(BeginDate.month, 13)]<p>
    lastyearmonths = [mn for mn in range(1, EndDate.month+1)]<p>
    months = [mn for mn in range(1, 13)]<p>
    numberofyearsbetween = EndDate.year - BeginDate.year - 1<p>
    return firstyearmonths + months * numberofyearsbetween + lastyearmonths<p>

#example
BD = datetime.datetime.strptime("2000-35", '%Y-%j')
ED = datetime.datetime.strptime("2004-200", '%Y-%j')
MonthsBetweenDates(BD, ED)

Solution 22 - Python

just like range function, when month is 13, go to next year

def year_month_range(start_date, end_date):
    '''
    start_date: datetime.date(2015, 9, 1) or datetime.datetime
    end_date: datetime.date(2016, 3, 1) or datetime.datetime
    return: datetime.date list of 201509, 201510, 201511, 201512, 201601, 201602
    '''
    start, end = start_date.strftime('%Y%m'), end_date.strftime('%Y%m')
    assert len(start) == 6 and len(end) == 6
    start, end = int(start), int(end)
    
    year_month_list = []
    while start < end:
        year, month = divmod(start, 100)
        if month == 13:
            start += 88  # 201513 + 88 = 201601
            continue
        year_month_list.append(datetime.date(year, month, 1))
    
        start += 1
    return year_month_list

example in python shell

>>> import datetime
>>> s = datetime.date(2015,9,1)
>>> e = datetime.date(2016, 3, 1)
>>> year_month_set_range(s, e)
[datetime.date(2015, 11, 1), datetime.date(2015, 9, 1), datetime.date(2016, 1, 1), datetime.date(2016, 2, 1),
 datetime.date(2015, 12, 1), datetime.date(2015, 10, 1)]

Solution 23 - Python

Usually 90 days are NOT 3 months literally, just a reference.

So, finally, you need to check if days are bigger than 15 to add +1 to month counter. or better, add another elif with half month counter.

From this other stackoverflow answer i've finally ended with that:

#/usr/bin/env python
# -*- coding: utf8 -*-

import datetime
from datetime import timedelta
from dateutil.relativedelta import relativedelta
import calendar

start_date = datetime.date.today()
end_date = start_date + timedelta(days=111)
start_month = calendar.month_abbr[int(start_date.strftime("%m"))]

print str(start_date) + " to " + str(end_date)

months = relativedelta(end_date, start_date).months
days = relativedelta(end_date, start_date).days

print months, "months", days, "days"

if days > 16:
    months += 1
    
print "around " + str(months) + " months", "(",

for i in range(0, months):
    print calendar.month_abbr[int(start_date.strftime("%m"))],
    start_date = start_date + relativedelta(months=1)
    
print ")"

Output:

2016-02-29 2016-06-14
3 months 16 days
around 4 months ( Feb Mar Apr May )

I've noticed that doesn't work if you add more than days left in current year, and that's is unexpected.

Solution 24 - Python

it seems that the answers are unsatisfactory and I have since use my own code which is easier to understand

from datetime import datetime
from dateutil import relativedelta

date1 = datetime.strptime(str('2017-01-01'), '%Y-%m-%d')
date2 = datetime.strptime(str('2019-03-19'), '%Y-%m-%d')

difference = relativedelta.relativedelta(date2, date1)
months = difference.months
years = difference.years
# add in the number of months (12) for difference in years
months += 12 * difference.years
months

Solution 25 - Python

Here is my solution for this:

def calc_age_months(from_date, to_date):
    from_date = time.strptime(from_date, "%Y-%m-%d")
    to_date = time.strptime(to_date, "%Y-%m-%d")

    age_in_months = (to_date.tm_year - from_date.tm_year)*12 + (to_date.tm_mon - from_date.tm_mon)

    if to_date.tm_mday < from_date.tm_mday:
        return age_in_months -1
    else
        return age_in_months

This will handle some edge cases as well where the difference in months between 31st Dec 2018 and 1st Jan 2019 will be zero (since the difference is only a day).

Solution 26 - Python

Assuming upperDate is always later than lowerDate and both are datetime.date objects:

if lowerDate.year == upperDate.year:
    monthsInBetween = range( lowerDate.month + 1, upperDate.month )
elif upperDate.year > lowerDate.year:
    monthsInBetween = range( lowerDate.month + 1, 12 )
    for year in range( lowerDate.year + 1, upperDate.year ):
        monthsInBetween.extend( range(1,13) )
    monthsInBetween.extend( range( 1, upperDate.month ) )

I haven't tested this thoroughly, but it looks like it should do the trick.

Solution 27 - Python

Try this:

 dateRange = [datetime.strptime(dateRanges[0], "%Y-%m-%d"),
             datetime.strptime(dateRanges[1], "%Y-%m-%d")]
delta_time = max(dateRange) - min(dateRange)
#Need to use min(dateRange).month to account for different length month
#Note that timedelta returns a number of days
delta_datetime = (datetime(1, min(dateRange).month, 1) + delta_time -
                           timedelta(days=1)) #min y/m/d are 1
months = ((delta_datetime.year - 1) * 12 + delta_datetime.month -
          min(dateRange).month)
print months

Shouldn't matter what order you input the dates, and it takes into account the difference in month lengths.

Solution 28 - Python

Here is a method:

def months_between(start_dt, stop_dt):
    month_list = []
    total_months = 12*(stop_dt.year-start_dt.year)+(stop_dt.month-start_d.month)+1
    if total_months > 0:
        month_list=[ datetime.date(start_dt.year+int((start_dt+i-1)/12), 
                                   ((start_dt-1+i)%12)+1,
                                   1) for i in xrange(0,total_months) ]
    return month_list

This is first computing the total number of months between the two dates, inclusive. Then it creates a list using the first date as the base and performs modula arithmetic to create the date objects.

Solution 29 - Python

I actually needed to do something pretty similar just now

Ended up writing a function which returns a list of tuples indicating the start and end of each month between two sets of dates so I could write some SQL queries off the back of it for monthly totals of sales etc.

I'm sure it can be improved by someone who knows what they're doing but hope it helps...

The returned value look as follows (generating for today - 365days until today as an example)

[   (datetime.date(2013, 5, 1), datetime.date(2013, 5, 31)),
    (datetime.date(2013, 6, 1), datetime.date(2013, 6, 30)),
    (datetime.date(2013, 7, 1), datetime.date(2013, 7, 31)),
    (datetime.date(2013, 8, 1), datetime.date(2013, 8, 31)),
    (datetime.date(2013, 9, 1), datetime.date(2013, 9, 30)),
    (datetime.date(2013, 10, 1), datetime.date(2013, 10, 31)),
    (datetime.date(2013, 11, 1), datetime.date(2013, 11, 30)),
    (datetime.date(2013, 12, 1), datetime.date(2013, 12, 31)),
    (datetime.date(2014, 1, 1), datetime.date(2014, 1, 31)),
    (datetime.date(2014, 2, 1), datetime.date(2014, 2, 28)),
    (datetime.date(2014, 3, 1), datetime.date(2014, 3, 31)),
    (datetime.date(2014, 4, 1), datetime.date(2014, 4, 30)),
    (datetime.date(2014, 5, 1), datetime.date(2014, 5, 31))]

Code as follows (has some debug stuff which can be removed):

#! /usr/env/python
import datetime

def gen_month_ranges(start_date=None, end_date=None, debug=False):
    today = datetime.date.today()
    if not start_date: start_date = datetime.datetime.strptime(
        "{0}/01/01".format(today.year),"%Y/%m/%d").date()  # start of this year
    if not end_date: end_date = today
    if debug: print("Start: {0} | End {1}".format(start_date, end_date))
    
    # sense-check
    if end_date < start_date:
        print("Error. Start Date of {0} is greater than End Date of {1}?!".format(start_date, end_date))
        return None
    
    date_ranges = []  # list of tuples (month_start, month_end)
    
    current_year = start_date.year
    current_month = start_date.month

    while current_year <= end_date.year:
        next_month = current_month + 1
        next_year = current_year
        if next_month > 12:
            next_month = 1
            next_year = current_year + 1
            
        month_start = datetime.datetime.strptime(
            "{0}/{1}/01".format(current_year,
                                current_month),"%Y/%m/%d").date()  # start of month
        month_end = datetime.datetime.strptime(
            "{0}/{1}/01".format(next_year,
                                next_month),"%Y/%m/%d").date()  # start of next month
        month_end  = month_end+datetime.timedelta(days=-1)  # start of next month less one day

        range_tuple = (month_start, month_end)
        if debug: print("Month runs from {0} --> {1}".format(
            range_tuple[0], range_tuple[1]))
        date_ranges.append(range_tuple)

        if current_month == 12:
            current_month = 1
            current_year += 1
            if debug: print("End of year encountered, resetting months")
        else:
            current_month += 1
            if debug: print("Next iteration for {0}-{1}".format(
                current_year, current_month))

        if current_year == end_date.year and current_month > end_date.month:
            if debug: print("Final month encountered. Terminating loop")
            break

    return date_ranges
    

if __name__ == '__main__':
    print("Running in standalone mode. Debug set to True")
    from pprint import pprint
    pprint(gen_month_ranges(debug=True), indent=4)
    pprint(gen_month_ranges(start_date=datetime.date.today()+datetime.timedelta(days=-365),
                            debug=True), indent=4)

Solution 30 - Python

Assuming that you wanted to know the "fraction" of the month that dates were in, which I did, then you need to do a bit more work.

from datetime import datetime, date
import calendar

def monthdiff(start_period, end_period, decimal_places = 2):
	if start_period > end_period:
		raise Exception('Start is after end')
	if start_period.year == end_period.year and start_period.month == end_period.month:
		days_in_month = calendar.monthrange(start_period.year, start_period.month)[1]
		days_to_charge = end_period.day - start_period.day+1
		diff = round(float(days_to_charge)/float(days_in_month), decimal_places)
		return diff
	months = 0
	# we have a start date within one month and not at the start, and an end date that is not
	# in the same month as the start date
	if start_period.day > 1:
		last_day_in_start_month = calendar.monthrange(start_period.year, start_period.month)[1]
		days_to_charge = last_day_in_start_month - start_period.day	+1
		months = months + round(float(days_to_charge)/float(last_day_in_start_month), decimal_places)
		start_period = datetime(start_period.year, start_period.month+1, 1)

	last_day_in_last_month = calendar.monthrange(end_period.year, end_period.month)[1]
	if end_period.day != last_day_in_last_month:
		# we have lest days in the last month
		months = months + round(float(end_period.day) / float(last_day_in_last_month), decimal_places)
		last_day_in_previous_month = calendar.monthrange(end_period.year, end_period.month - 1)[1]
		end_period = datetime(end_period.year, end_period.month - 1, last_day_in_previous_month)

	#whatever happens, we now have a period of whole months to calculate the difference between

	if start_period != end_period:
		months = months + (end_period.year - start_period.year) * 12 + (end_period.month - start_period.month) + 1

	# just counter for any final decimal place manipulation
	diff = round(months, decimal_places)
	return diff

assert monthdiff(datetime(2015,1,1), datetime(2015,1,31)) == 1
assert monthdiff(datetime(2015,1,1), datetime(2015,02,01)) == 1.04
assert monthdiff(datetime(2014,1,1), datetime(2014,12,31)) == 12
assert monthdiff(datetime(2014,7,1), datetime(2015,06,30)) == 12
assert monthdiff(datetime(2015,1,10), datetime(2015,01,20)) == 0.35
assert monthdiff(datetime(2015,1,10), datetime(2015,02,20)) == 0.71 + 0.71
assert monthdiff(datetime(2015,1,31), datetime(2015,02,01)) == round(1.0/31.0,2) + round(1.0/28.0,2)
assert monthdiff(datetime(2013,1,31), datetime(2015,02,01)) == 12*2 + round(1.0/31.0,2) + round(1.0/28.0,2)

provides an example that works out the number of months between two dates inclusively, including the fraction of each month that the date is in. This means that you can work out how many months is between 2015-01-20 and 2015-02-14, where the fraction of the date in the month of January is determined by the number of days in January; or equally taking into account that the number of days in February can change form year to year.

For my reference, this code is also on github - https://gist.github.com/andrewyager/6b9284a4f1cdb1779b10

Solution 31 - Python

This works...

from datetime import datetime as dt
from dateutil.relativedelta import relativedelta
def number_of_months(d1, d2):
    months = 0
    r = relativedelta(d1,d2)
    if r.years==0:
        months = r.months
    if r.years>=1:
        months = 12*r.years+r.months
    return months
#example 
number_of_months(dt(2017,9,1),dt(2016,8,1))

Solution 32 - Python

from datetime import datetime

def diff_month(start_date,end_date):
	qty_month = ((end_date.year - start_date.year) * 12) + (end_date.month - start_date.month)

	d_days = end_date.day - start_date.day

	if d_days >= 0:
		adjust = 0
	else:
		adjust = -1
	qty_month += adjust

	return qty_month

diff_month(datetime.date.today(),datetime(2019,08,24))


#Examples:
#diff_month(datetime(2018,02,12),datetime(2019,08,24)) = 18
#diff_month(datetime(2018,02,12),datetime(2018,08,10)) = 5

Solution 33 - Python

This is my way to do this:

Start_date = "2000-06-01"
End_date   = "2001-05-01"

month_num  = len(pd.date_range(start = Start_date[:7], end = End_date[:7] ,freq='M'))+1

I just use the month to create a date range and calculate the length.

Solution 34 - Python

To get the number of full months between two dates:

import datetime

def difference_in_months(start, end):
    if start.year == end.year:
        months = end.month - start.month
    else:
        months = (12 - start.month) + (end.month)

    if start.day > end.day:
        months = months - 1

    return months

Solution 35 - Python

You can use the below code to get month between two dates:

OrderedDict(((start_date + timedelta(_)).strftime(date_format), None) for _ in xrange((end_date - start_date).days)).keys()

where start_date and end_date must be proper date and date_format is the format in which you want your result of date..

In your case, date_format will be %b %Y.

Solution 36 - Python

The question, is really asking about the total months between 2 dates and not the difference of it

Hence a revisited answer with some extra functionallity,

from datetime import date, datetime
from dateutil.rrule import rrule, MONTHLY

def month_get_list(dt_to, dt_from, return_datetime=False, as_month=True):
    INDEX_MONTH_MAPPING = {1: 'january', 2: 'february', 3: 'march', 4: 'april', 5: 'may', 6: 'june', 7: 'july',
                           8: 'august',
                           9: 'september', 10: 'october', 11: 'november', 12: 'december'}
    if return_datetime:
        return [dt for dt in rrule(MONTHLY, dtstart=dt_from, until=dt_to)]
    if as_month:
        return [INDEX_MONTH_MAPPING[dt.month] for dt in rrule(MONTHLY, dtstart=dt_from, until=dt_to)]

    return [dt.month for dt in rrule(MONTHLY, dtstart=dt_from, until=dt_to)]

month_list = month_get_list(date(2021, 12, 31), date(2021, 1, 1))
total_months = len(month_list)

Result

month_list = ['january', 'february', 'march', 'april', 'may', 'june', 'july', 'august', 'september', 'october', 'november', 'december']
total_months = 12

With as_month set to False

month_list = month_get_list(date(2021, 12, 31), date(2021, 1, 1),

as_month=False)
# month_list = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]

Returing datetime instead

month_list = month_get_list(date(2021, 12, 31), date(2021, 1, 1), return_datetime=True)
month_list = [datetime.datetime(2021, 1, 1, 0, 0), datetime.datetime(2021, 2, 1, 0, 0), datetime.datetime(2021, 3, 1, 0, 0), datetime.datetime(2021, 4, 1, 0, 0), datetime.datetime(2021, 5, 1, 0, 0), datetime.datetime(2021, 6, 1, 0, 0), datetime.datetime(2021, 7, 1, 0, 0), datetime.datetime(2021, 8, 1, 0, 0), datetime.datetime(2021, 9, 1, 0, 0), datetime.datetime(2021, 10, 1, 0, 0), datetime.datetime(2021, 11, 1, 0, 0), datetime.datetime(2021, 12, 1, 0, 0)]

Solution 37 - Python

If fractions of month are important to you, leverage the first day of the next month to work around the number of days each month may have, on a step year or not:

from datetime import timedelta, datetime
from dateutil.relativedelta import relativedelta

def month_fraction(this_date):
    	this_date_df=this_date.strftime("%Y-%m-%d")
    	day1_same_month_as_this_date_df=this_date_df[:8]+'01'
        day1_same_month_as_this_date=datetime.strptime(day1_same_month_as_this_date_df, '%Y-%m-%d').date()
    	next_mon	th_as_this_date=this_date+relativedelta(months=1)
    	next_month_as_this_date_df=next_month_as_this_date.strftime("%Y-%m-%d")
    	day1_next_month_this_date_df=next_month_as_this_date_df[:8]+'01'
    	day1_next_month_this_date=datetime.strptime(day1_next_month_this_date_df, '%Y-%m-%d').date()
    	last_day_same_month_this_date=day1_next_month_this_date-timedelta(days=1)
    	delta_days_from_month_beginning=(this_date-day1_same_month_as_this_date).days
    	delta_days_whole_month=(last_day_same_month_this_date-day1_same_month_as_this_date).days    
    	fraction_beginning_of_month=round(delta_days_from_month_beginning/delta_days_whole_month,4)
    	return fraction_beginning_of_month

def delta_months_JLR(second_date,first_date):
    	return (second_date.year - first_date.year) * 12 + second_date.month - first_date.month

def delta_months_float(first_date,second_date):
    	outgoing_fraction_first_date  =  month_fraction(first_date)
    	incoming_fraction_second_date  =  month_fraction(second_date)
    	delta_months=delta_months_JLR(second_date,first_date) #as on John La Rooy’s response
    	months_float=round(delta_months-outgoing_fraction_first_date+incoming_fraction_second_date,4)
    	return months_float


first_date_df='2021-12-28'
first_date=datetime.strptime(first_date, '%Y-%m-%d').date()
second_date_df='2022-01-02'
second_date=datetime.strptime(second_date, '%Y-%m-%d').date()

print (delta_months_float(first_date,second_date))
0.1333

Solution 38 - Python

You could use something like:

import datetime
days_in_month = 365.25 / 12  # represent the average of days in a month by year
month_diff = lambda end_date, start_date, precision=0: round((end_date - start_date).days / days_in_month, precision)
start_date = datetime.date(1978, 12, 15)
end_date = datetime.date(2012, 7, 9)
month_diff(end_date, start_date)  # should show 403.0 months

Solution 39 - Python

import datetime
from calendar import monthrange

def date_dif(from_date,to_date):   # Изчислява разлика между две дати
    dd=(to_date-from_date).days
    if dd>=0:
        fromDM=from_date.year*12+from_date.month-1
        toDM=to_date.year*12+to_date.month-1
        mlen=monthrange(int((toDM)/12),(toDM)%12+1)[1]
        d=to_date.day-from_date.day
        dm=toDM-fromDM
        m=(dm-int(d<0))%12
        y=int((dm-int(d<0))/12)
        d+=int(d<0)*mlen
        # diference in Y,M,D, diference months,diference  days, days in to_date month
        return[y,m,d,dm,dd,mlen]
    else:
        return[0,0,0,0,dd,0]

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionJoshkunzView Question on Stackoverflow
Solution 1 - PythonJohn La RooyView Answer on Stackoverflow
Solution 2 - PythonN1B4View Answer on Stackoverflow
Solution 3 - Pythonaamir23View Answer on Stackoverflow
Solution 4 - PythonNazarii GudzovatyiView Answer on Stackoverflow
Solution 5 - PythonyatabaniView Answer on Stackoverflow
Solution 6 - PythonVin-GView Answer on Stackoverflow
Solution 7 - PythonsrodriguexView Answer on Stackoverflow
Solution 8 - PythonHottabovView Answer on Stackoverflow
Solution 9 - PythonSethView Answer on Stackoverflow
Solution 10 - PythonnonopolarityView Answer on Stackoverflow
Solution 11 - Pythonconner.xyzView Answer on Stackoverflow
Solution 12 - PythonH4kimView Answer on Stackoverflow
Solution 13 - PythonDaniel ReisView Answer on Stackoverflow
Solution 14 - PythonsaajView Answer on Stackoverflow
Solution 15 - PythonLuis Alberto SantanaView Answer on Stackoverflow
Solution 16 - PythonCharles HooperView Answer on Stackoverflow
Solution 17 - PythonsandinmyjointsView Answer on Stackoverflow
Solution 18 - Pythonpankaj kumarView Answer on Stackoverflow
Solution 19 - PythonYogesh KushwahaView Answer on Stackoverflow
Solution 20 - PythonArpan SainiView Answer on Stackoverflow
Solution 21 - PythonMehmet ErcanView Answer on Stackoverflow
Solution 22 - PythonWeizhongTuView Answer on Stackoverflow
Solution 23 - Pythonm3ndaView Answer on Stackoverflow
Solution 24 - PythongrandiaView Answer on Stackoverflow
Solution 25 - PythonGaurav AgarwalView Answer on Stackoverflow
Solution 26 - PythonScottView Answer on Stackoverflow
Solution 27 - Pythonom_hennersView Answer on Stackoverflow
Solution 28 - PythonDanView Answer on Stackoverflow
Solution 29 - PythonJamesView Answer on Stackoverflow
Solution 30 - PythonAndrew YagerView Answer on Stackoverflow
Solution 31 - PythonGeorge PamfilisView Answer on Stackoverflow
Solution 32 - PythonMax SandovalView Answer on Stackoverflow
Solution 33 - PythonArthurView Answer on Stackoverflow
Solution 34 - PythonpieguyView Answer on Stackoverflow
Solution 35 - PythonakshaypjoshiView Answer on Stackoverflow
Solution 36 - PythonFederico BaùView Answer on Stackoverflow
Solution 37 - PythonAl MartinsView Answer on Stackoverflow
Solution 38 - PythonDubasView Answer on Stackoverflow
Solution 39 - PythonGES-2000View Answer on Stackoverflow