考虑日历月中不相等的天数,增加/减去月份



我正试图想出一种方法来创建日期n个月从给定日期dt的列表。然而,这似乎是棘手的基于什么dt是。下面我将通过几个例子来说明这个困境(特别是下面的棘手案例3):

from datetime import datetime
from dateutil.relativedelta import relativedelta
# Simple case.
dt = datetime(2021, 2, 15)
dt - relativedelta(months=1)  # n=1 gives datetime.datetime(2021, 1, 15, 0, 0)
dt - relativedelta(months=2)  # n=2 gives datetime.datetime(2020, 12, 15, 0, 0)
# Simple case-2
dt = datetime(2021, 3, 31)
dt - relativedelta(months=1)  # n=1 gives datetime.datetime(2021, 2, 28, 0, 0)
dt - relativedelta(months=2)  # n=2 gives datetime.datetime(2021, 1, 31, 0, 0)
dt - relativedelta(months=3)  # n=3 gives datetime.datetime(2020, 12, 31, 0, 0)
dt - relativedelta(months=4)  # n=4 gives datetime.datetime(2020, 11, 30, 0, 0)
# Tricky case-3
dt = datetime(2021, 2, 28)
dt - relativedelta(months=1)  # n=1 gives datetime.datetime(2021, 1, 28, 0, 0) and not datetime.datetime(2021, 1, 31, 0, 0)
dt - relativedelta(months=2)  # n=2 gives datetime.datetime(2020, 12, 28, 0, 0) and not datetime.datetime(2020, 12, 31, 0, 0)
dt - relativedelta(months=3)  # n=3 gives datetime.datetime(2020, 11, 28, 0, 0) and not datetime.datetime(2020, 11, 30, 0, 0)
dt - relativedelta(months=4)  # n=4 gives datetime.datetime(2020, 10, 28, 0, 0) and not datetime.datetime(2020, 10, 31, 0, 0)

relativedelta对于日期是月底而月少于31天的角情况似乎给出了意想不到的结果。这里有一个变通方法:

  • 检查日期是否为月底
  • 如果不是,则直接使用relativedelta
  • ifso,使用relativedelta,但通过显式设置day属性来确保日期是该月的最后一天
from datetime import datetime, timedelta
from dateutil.relativedelta import relativedelta
# add_month adds n months to datetime object dt
def add_month(dt, n):
# we can add a day without month changing - not end of month:
if (dt + timedelta(1)).month == dt.month:
return dt + relativedelta(months=n)
# implicit else: end of month
return (dt + relativedelta(months=n+1)).replace(day=1) - timedelta(1)

例子:

d = datetime(2021, 3, 15)
print(add_month(d, -1).date(), d.date(), add_month(d, 1).date())
# 2021-02-15 2021-03-15 2021-04-15
d = datetime(2021, 3, 31)
print(add_month(d, -1).date(), d.date(), add_month(d, 1).date())
# 2021-02-28 2021-03-31 2021-04-30
d = datetime(2021,2,28)
print(add_month(d, -1).date(), d.date(), add_month(d, 1).date())
# 2021-01-31 2021-02-28 2021-03-31
d = datetime(2021,11,30)
print(add_month(d, -1).date(), d.date(), add_month(d, 1).date())
# 2021-10-31 2021-11-30 2021-12-31

相关内容

  • 没有找到相关文章

最新更新