Python 中找出两个日期间隔月份的最佳方法

我需要能够在 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 格式转换成 python datetime 对象。然后我循环添加一个星期到 start datetime 对象,检查这个月的数值是否更大(除非这个月是十二月,然后它检查这个日期是否更小) ,如果值更大,我将它追加到这个月的列表中,然后继续循环,直到我到达我的结束日期。

它能工作,只是看起来不像是一个很好的方法..。

235465 次浏览

尝试这样的东西。它目前包括一个月,如果两个日期碰巧在同一个月。

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]

更新2018-04-20: 似乎 OP@Joshkunz 要求寻找 哪几个月是在两个日期之间,而不是“多少个月”是在两个日期之间。所以我不知道为什么@JohnLaRooy 的支持率超过了100次。@ Joshkunz 在原问题下的评论中表示,他想要的是实际的日期[或月份] ,而不是找到 月份总数

因此,这似乎是一个需要解决的问题,因为在 2018-04-112018-06-01的两个日期之间

Apr 2018, May 2018, June 2018

如果是在 2014-04-112018-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)

现在只是伪代码,还没有测试,但我认为沿着同一行的想法将工作。

假设 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 ) )

我还没有彻底测试过,但看起来应该可以。

将“月份”定义为 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天(取决于年份)”。但是如果你这么做了,你还有一个额外的问题要解决。

虽然通常很清楚6月15这个 + 1个月应该是7月15这个,但通常不清楚1月30这个 + 1个月是2月还是3月。在后一种情况下,您可能被迫计算日期为2月30这个,然后“更正”到3月2。但是当你这样做的时候,你会发现3月2-1个月明显是2月2。因此,反证法(这个操作没有很好的定义)。

试试这个:

 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

无论你输入日期的顺序是什么,它都会考虑到月份长度的差异。

获取结束月份(相对于开始月份的年份和月份 ex: 2011 January = 13,如果你的开始日期从2010年10月开始) ,然后生成开始月份和结束月份的日期时间,如下所示:

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)]

这里有一个方法:

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

这是首先计算两个日期之间的月份总数,包括。然后,它使用第一个日期作为基础创建一个列表,并执行模运算来创建日期对象。

首先定义一些测试用例,然后您将看到函数非常简单,不需要循环

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

您应该在您的问题中添加一些测试用例,因为有许多潜在的角落用例需要覆盖——有不止一种方法来定义两个日期之间的月数。

有一个基于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))

你可以使用这样的东西:

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
#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)

@ 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 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)]

其实我刚才也需要做一些类似的事情

最后我写了一个函数,它返回一个元组列表,表示两组日期之间每个月的 startend,这样我就可以在后面写一些 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
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

希望这个能帮上忙!

使用一行程序查找日期时间列表,该列表在两个日期之间按月递增。

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)]

这对我很管用

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)

假设你想知道日期所在月份的“分数”,我就是这么做的,那么你需要做更多的工作。

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)

提供一个示例,计算两个日期之间的月数(包括该日期所在的每个月的分数)。这意味着你可以计算出2015-01-20和2015-02-14之间的月份数,其中1月份日期的分数是由1月份的天数决定的; 或者同样考虑到2月份的天数可以年复一年地变化。

供我参考,这段代码也在 github-https://gist.github.com/andrewyager/6b9284a4f1cdb1779b10

就像 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 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)]

通常90天不是3个月字面上,只是一个参考。

因此,最后,您需要检查天数是否大于15,以添加 + 1到月计数器。或者更好,加上另一个精灵与半个月柜台。

另一个堆栈溢出的答案节目开始,我最后以这句话作为结束:

#/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 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))

以下是对待熊猫的方法:

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')

注意,它以给定的开始日期 之后月份开始。

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

我的简单解决办法:

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))

可以使用 datetime.timedelta 完成,其中可以通过 calender.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])

`

看起来答案并不令人满意,从那以后我使用了我自己的代码,它更容易理解

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

我是这么做的:

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

我只是使用月份来创建一个日期范围并计算长度。

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]
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 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']


要获取两次约会之间的整月数:

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

我的解决办法是:

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

这也将处理一些边缘情况,其中2018年12月31日至2019年1月1日之间的月份差额为零(因为差额只有一天)。

from dateutil import relativedelta


r = relativedelta.relativedelta(date1, date2)


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

您可以使用下面的代码来获取两个日期之间的月份:

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

其中 start_dateend_date必须是正确的 date,date _ format 是您希望获得日期结果的格式。.

在您的情况下,date_format将是 %b %Y

得到两个日期之间的天数、月数和年数的差异。

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)

这个问题,实际上是问关于 两个日期之间的总月份,而不是它的差异

因此,一个带有一些额外功能的重新访问的 回答,

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)

结果

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

按月计算设置为 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]

而是返回日期时间

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)]

如果月份的某些部分对你来说很重要,那么利用下个月的第一天来计算每个月的工作天数,不管是一个步骤的一年还是另一个步骤的一年:

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

请给出开始和结束日期及以下功能将罚款整个月的开始和结束日期。

$months = $this->getMonthsInRange('2022-03-15', '2022-07-12');
    

    

public function getMonthsInRange($startDate, $endDate)
{
$months = array();
while (strtotime($startDate) <= strtotime($endDate)) {
$start_date = date('Y-m-d', strtotime($startDate));
$end_date = date("Y-m-t", strtotime($start_date));
if(strtotime($end_date) >= strtotime($endDate)) {
$end_date = $endDate;
}
$months[] = array(
'start_date' => $start_date,
'end_date' => $end_date
);
$startDate = date('01 M Y', strtotime($startDate . '+ 1 month'));
}
return $months;
}

对于 python3工作良好

    import datetime


start = datetime.datetime.today()
end = start + datetime.timedelta(days=365)
month_range = [start.date()]
diff = end - start
months = round(diff.days / 30)
temp = start
    

for i in range(months):
temp = temp + datetime.timedelta(days=30)
if temp <= end:
month_range.append(temp.date())


print(month_range)