Python计算两个日期相差月数的实现方案
本文针对Python标准库及dateutil模块在计算两个日期相差月数时存在的精度或功能缺失问题,提供了一套自定义解决方案。通过对比rrule模块的测试结果,展示了手动处理大小月及闰年差异的方法,最终实现返回整数月与小数月的精确计算结果。
近期因业务需求,需要计算两个日期之间相隔的月数。经过搜索发现,Python中似乎缺乏直接计算两个日期月数差的内置模块。相比之下,Java、C#等语言通常提供如(date1-date2).months这样的现成方法。对此结果感到意外,同时也觉得Python的日期处理模块在实际使用中并不够便捷。
需要说明的是,datetime、calendar以及dateutil等常见模块均已被尝试,但未能直接满足需求。其中部分模块甚至存在计算错误。具体而言,datetime.timedelta仅支持计算日、时、分、秒的差值,对年和月的处理并不支持。网络上虽然存在大量相关讨论,但往往难以直接适用。
网上流传较广的dateutil.rrule示例,经实际测试发现结果存在偏差,具体测试情况如下所示:
import datetime
from dateutil import rrule
d1 = datetime.date(2016, 2, 29)
d2 = datetime.date(2019, 3, 31)
months = rrule.rrule(rrule.MONTHLY, dtstart=d1, until=d2).count()
print(f"months={months}")

面对上述测试结果,该方案显然不可靠。
因此,下面提供一段自行编写的代码以实现准确计算:
该代码执行后,将返回包含整数月和小数月的结果元组。
import datetime
import calendar as c
d1 = datetime.date(2016, 2, 29)
d2 = datetime.date(2019, 3, 31)
def calmonths(startdate, enddate):
# 计算两个日期相隔月差
samemonthdate = None
try:
samemonthdate = datetime.date(enddate.year, enddate.month,
startdate.day)
except Exception as e:
print(e)
samemonthdate = datetime.date(enddate.year, enddate.month,
c.monthrange(enddate.year,
enddate.month)[1])
holdmonths = 0
decimalmonth = 0.0
if samemonthdate > enddate:
premanthdate = None
try:
premanthdate = datetime.date(enddate.year, enddate.month - 1,
startdate.day)
except Exception as e:
print(e)
premanthdate = datetime.date(enddate.year, enddate.month - 1,
c.monthrange(
enddate.year,
enddate.month - 1)[1])
currmonthdays = (samemonthdate - premanthdate).days
holdmonths = (premanthdate.year - startdate.year
) * 12 + premanthdate.month - startdate.month
decimalmonth = (enddate - premanthdate).days / currmonthdays
elif samemonthdate < enddate:
nextmonthdate = None
try:
nextmonthdate = datetime.date(enddate.year, enddate.month + 1,
startdate.day)
except Exception as e:
nextmonthdate = datetime.date(enddate.year, enddate.month + 1,
c.monthrange(
enddate.year,
enddate.month + 1)[1])
currmonthdays = (nextmonthdate - samemonthdate).days
holdmonths = (samemonthdate.year - startdate.year
) * 12 + samemonthdate.month - startdate.month
decimalmonth = (enddate - samemonthdate).days / currmonthdays
else:
holdmonths = (enddate.year - startdate.year
) * 12 + enddate.month - startdate.month
return holdmonths, decimalmonth
months = calmonths(d1, d2)
print(f"months={months}")

以上即为本文分享的全部内容,希望能为读者在相关场景下的学习与应用提供参考,欢迎继续支持。
免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。









