Мне нужно иметь возможность точно находить месяцы между двумя датами в python. У меня есть решение, которое работает, но не очень хорошее (например, элегантное) или быстрое.
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
Чтобы объяснить, что я здесь делаю, это беру две даты и конвертирую их из формата iso в объекты datetime python. Затем я добавляю неделю к объекту start datetime и проверяю, больше ли числовое значение месяца (если месяц не декабрь, тогда он проверяет, меньше ли дата). Если значение больше, я добавляю его в список месяцев и продолжайте повторять, пока я не доберусь до даты окончания.
Он работает отлично, просто не похоже на хороший способ сделать это ...
python
datetime
monthcalendar
date-math
Йошкунц
источник
источник
Ответы:
Обновление 2018-04-20: похоже, что OP @Joshkunz просил выяснить, какие месяцы находятся между двумя датами, а не «сколько месяцев» между двумя датами. Поэтому я не уверен, почему за @JohnLaRooy проголосовали более 100 раз. @Joshkunz указал в комментарии под исходным вопросом, что ему нужны реальные даты [или месяцы], вместо того, чтобы найти общее количество месяцев .
Таким образом, возник вопрос, который требовался от двух дат
2018-04-11
до2018-06-01
Apr 2018, May 2018, June 2018
А что , если он находится между
2014-04-11
к2018-06-01
? Тогда ответ был быApr 2014, May 2014, ..., Dec 2014, Jan 2015, ..., Jan 2018, ..., June 2018
Вот почему много лет назад у меня был следующий псевдокод. Он просто предлагал использовать два месяца в качестве конечных точек и проходить их в цикле, увеличиваясь на один месяц за раз. @Joshkunz упомянул, что ему нужны «месяцы», и он также упомянул, что ему нужны «даты», не зная точно, было сложно написать точный код, но идея состоит в том, чтобы использовать один простой цикл для перебора конечных точек и с шагом один месяц за раз.
Ответ 8 лет назад в 2010 году:
Если добавить на неделю, то он будет выполнять работу примерно в 4,35 раза больше, чем необходимо. Почему не просто:
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)
пока только псевдо-код, не тестировал, но я думаю, что идея в том же направлении сработает.
источник
1
до2
, а затем от2
до3
.Начните с определения некоторых тестовых примеров, тогда вы увидите, что функция очень проста и не требует циклов.
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
Вы должны добавить несколько тестовых примеров к вашему вопросу, так как есть много потенциальных угловых случаев, которые нужно охватить - существует более одного способа определить количество месяцев между двумя датами.
источник
Один лайнер для поиска списка дат и времени, увеличенных по месяцам, между двумя датами.
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)]
источник
[dt for dt in rrule(MONTHLY, bymonthday=10,dtstart=strt_dt, until=end_dt)]
start_date_first = start_date.replace(day=1), end_date_first = end_date.replace(day=1)
тогда rrule правильно считает месяцы.Это сработало для меня -
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)
источник
str()
строковые литералы.r.months
начнется с 0Вы можете легко рассчитать это, используя rrule из модуля dateutil :
from dateutil import rrule from datetime import date print(list(rrule.rrule(rrule.MONTHLY, dtstart=date(2013, 11, 1), until=date(2014, 2, 1))))
даст тебе:
[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)]
источник
Получите конечный месяц (относительно года и месяца начального месяца, например: 2011 января = 13, если ваша начальная дата начинается в октябре 2010 года), а затем сгенерируйте дату и время начала месяца начала и этого месяца окончания следующим образом:
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) )]
если обе даты относятся к одному году, это можно также просто записать как:
dates=[datetime.datetime(year=dt1.year, month=mn, day=1) for mn in range(dt1.month, dt2.month + 1)]
источник
В этом посте это доказано! Используйте
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
источник
str()
слепок, который я сделал, совершенно не нужен.relativedelta.relativedelta(date2, date1).years * 12
delta.years*12 + delta.months
Мое простое решение:
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))
источник
from dateutil import relativedelta relativedelta.relativedelta(date1, date2) months_difference = (r.years * 12) + r.months
источник
Определение «месяц» , как 1 / 12 года, то сделать это:
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
Вы можете попробовать определить месяц как «период в 29, 28, 30 или 31 день (в зависимости от года)». Но если вы сделаете это, вам нужно будет решить дополнительную проблему.
Хотя это, как правило , ясно , что 15 июня й + 1 месяц должно быть 15 июля - го , это не правило , не ясно , если 30 января е + 1 месяц в феврале или марте. В последнем случае, вы можете быть вынуждены вычислять дату как 30 февраля - го , то «правильно» его 2 марта - го . Но когда вы сделаете это, вы обнаружите , что 2 марта й - 1 месяц, очевидно , 2 февраля - го . Ergo, reductio ad absurdum (эта операция плохо определена).
источник
Существует простое решение, основанное на 360-дневных годах, где во всех месяцах 30 дней. Он подходит для большинства случаев использования, когда для двух дат необходимо рассчитать количество полных месяцев плюс оставшиеся дни.
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))
источник
Немного приукрашенное решение от @ 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)
источник
Вы также можете использовать библиотеку стрелок . Это простой пример:
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')
Это напечатает:
1 January 2 February 3 March 4 April 5 May 6 June
Надеюсь это поможет!
источник
Попробуйте что-нибудь подобное. В настоящее время он включает месяц, если обе даты находятся в одном месяце.
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
Результат выглядит так:
>>> start = datetime.now() - timedelta(days=120) >>> end = datetime.now() >>> months_between(start,end) [6, 7, 8, 9, 10]
источник
Вы можете использовать python-dateutil . См. Python: разница двух дат в месяцах
источник
Вот как это сделать с помощью 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')
Обратите внимание, что он начинается с месяца после указанной даты начала.
источник
Это можно сделать с помощью datetime.timedelta, где количество дней для перехода к следующему месяцу можно получить с помощью calender.monthrange. monthrange возвращает день недели (0-6 ~ пн-вс) и количество дней (28-31) для данного года и месяца.
Например: monthrange (2017, 1) возвращает (6,31).
Вот сценарий, использующий эту логику для итерации между двумя месяцами.
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])
`
источник
Многие люди уже дали вам хорошие ответы для решения этой проблемы, но я не читал ни одного использования понимания списков, поэтому я даю вам то, что использовал для аналогичного варианта использования:
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']
источник
#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)
источник
как и
range
функция, когда месяц 13 , перейти к следующему году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
пример в оболочке Python
>>> 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)]
источник
Обычно 90 дней - это НЕ 3 месяца в буквальном смысле, это просто справка.
Итак, наконец, вам нужно проверить, больше ли дней 15, чтобы добавить +1 к счетчику месяцев. или лучше добавить еще один элиф с полумесячным счетчиком.
Из этого другого ответа stackoverflow я наконец закончил:
#/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 ")"
Выход:
2016-02-29 2016-06-14 3 months 16 days around 4 months ( Feb Mar Apr May )
Я заметил, что это не сработает, если вы добавите больше дней, оставшихся в текущем году, и это неожиданно.
источник
кажется, что ответы неудовлетворительны, и с тех пор я использую свой собственный код, который легче понять
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
источник
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
источник
Вот мое решение для этого:
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
Это также будет обрабатывать некоторые крайние случаи, когда разница в месяцах между 31 декабря 2018 года и 1 января 2019 года будет равна нулю (поскольку разница составляет всего один день).
источник
Предполагая, что upperDate всегда позже lowerDate, и оба являются объектами datetime.date:
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 ) )
Я не тестировал это полностью, но похоже, что это должно помочь.
источник
Вот способ:
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
Это первое вычисление общего количества месяцев между двумя датами включительно. Затем он создает список, используя первую дату в качестве основы, и выполняет модульную арифметику для создания объектов даты.
источник
Мне прямо сейчас нужно было сделать что-то похожее
Закончил написание функции, которая возвращает список кортежей с указанием
start
иend
каждого месяца между двумя наборами дат, чтобы я мог написать несколько SQL-запросов для ежемесячных итогов продаж и т. Д.Я уверен, что его может улучшить кто-то, кто знает, что делает, но надеюсь, что это поможет ...
Возвращаемое значение выглядит следующим образом (сгенерировано на сегодня - например, с 365 дней до сегодняшнего дня)
[ (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))]
Код следующим образом (есть некоторые отладочные данные, которые можно удалить):
#! /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)
источник
Предполагая, что вы хотели узнать «долю» месяца, в которой были даты, что я и сделал, вам нужно проделать немного больше работы.
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)
предоставляет пример, который вычисляет количество месяцев между двумя датами включительно, включая долю каждого месяца, в котором указана дата. Это означает, что вы можете вычислить, сколько месяцев находится между 20.01.2015 и 14.02.2015 , где доля числа в январе определяется количеством дней в январе; в равной степени с учетом того, что количество дней в феврале может меняться из года в год.
Для справки, этот код также есть на github - https://gist.github.com/andrewyager/6b9284a4f1cdb1779b10
источник
Попробуй это:
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
Не имеет значения, в каком порядке вы вводите даты, он учитывает разницу в длине месяцев.
источник
Это работает...
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))
источник