一、需求简化

给定一个日期(如2022-11-13)和天数n,写一个算法,计算出n天后的日期。
示例:
输入内容:
(2022-11-13, 1000)
输出内容:
2025-08-09

二、解题思路

2.1 重点和难点

我觉得重点是在考核闰年的判定问题,闰年的2月分29天,其他年份都是28天。
闰年判断逻辑:四年一闰,百年不闰,四百年又闰。

难点则是日期的“进制”问题,这个跟十进制的逢十进一的逻辑有点类似:日满进月,月满进年。
但是每个月的天数可能会有所不同,而且会受到闰年的影响,如何实现日满进月便成了一个难点。

2.2 代码实现

了解了重点和难点之后,可能还是会一脸疑惑。像我一开始也是无从下手,后来想着从年到月再到日,但是经过一番思索之后,发现似乎行不通,就是因为月满进年,最终的年份并不能直接将天数除以365向下取整,再加上输入的年份得到,比如我举得这个例子int(1000/365)+2022等于2024,并非结果的2025。依照这样的逻辑,会把问题变得很复杂。
既然年->月->日的顺序跑不通,那就试试反过来日->月->年,即通过循环,循环一次当做一天,然后通过n次循环,加上n天,在日上不断加1,直到涉及日满进月,月满进年的逻辑。

为了解决日满进月的功能,可以拆开来思考,首先解决月份的问题,然后再考虑闰年的影响。

  • 月份问题:由于天数不同,那可以考虑将天数通过列表存放,然后通过索引来获取每月的天数,然后和实际日进行比较。
  • 细节点:将所有月份的天数按月份顺序放到一个列表中,然后可以用(月份数字-1)进行索引取出对应的天数进行大小判断,大于月份天数时则给月份加一,然后日赋值1,即下月1日开始继续计算。
  • 闰年问题:解决闰年的影响,可以单独写一个判断,判断年份是否是闰年,是则修改列表的2月天数为29天,非闰年则保持28天
  • 细节点:闰年时赋值为29之后,列表的值会改变,非闰年时需要进行重新赋值为28,避免非闰年也按29天计算。

最后附上看看我的解法,逻辑不难,但是细节点有很多,相关内容都已做好注释,需要细心思考并验证。

def add_date(date, n):
    year = int(date.split('-')[0])    # 年
    month = int(date.split('-')[1])   # 月
    day = int(date.split('-')[2])     # 日
    per_month_days = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]  # 12个月每月天数

    for i in range(n):
        if (year % 400) == 0 or (year % 4 == 0 and year % 100 != 0):   # 四年一闰,百年不闰,四百年再闰
            per_month_days[1] = 29    # 闰年29天
        else:
            per_month_days[1] = 28    # 非闰年28天,注意不能少该判断,因为如果被赋值29之后,在非闰年需要改回28
        """
        判断日是否小于每月对应的天数,少则在循环时加1,
        如果等于或大于,则day赋值为1,月份加1;
        月份加1之前也需要判断月份是否小于12,如果小于12,直接加1即可,
        如果等于或大于12,则需将月份赋值为1,年份加1.
        """
        if day < per_month_days[month-1]:
            day += 1
        else:
            day = 1
            if month < 12:
                month += 1
            else:
                month = 1
                year += 1
    return '%d-%02d-%02d' % (year, month, day)  # 指定格式,月日都是两位,不够补0

if __name__ == '__main__':
    date = '2022-11-13'
    n = 1000
    result_date = add_date(date, n)
    print(result_date)