代码之家  ›  专栏  ›  技术社区  ›  Gerry

考虑日历月中不平等的天数,添加/扣除月份

  •  0
  • Gerry  · 技术社区  · 4 年前

    我正在想办法创建一个日期列表 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)
    
    0 回复  |  直到 4 年前
        1
  •  1
  •   FObersteiner Peter White    4 年前

    relativedelta 似乎在的角落案例中失败了 日期是月底,而月的天数少于31天 。以下是解决方法:

    • 检查日期是否为月末
    • 如果 ,简单使用 relativedelta
    • 如果 所以 ,使用relativelta,但通过显式设置day属性来确保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