Python中add_months函数aux_date无法递增问题及修正咨询
日期增加月份函数的问题解析
问题背景
编写了用于给日期增加指定月份的Python函数add_months,但原函数运行时发现aux_date变量未在循环中逐步累加月份天数,反而每次基于原始日期计算,导致日期无法递增。
原函数代码
import re, datetime def add_months(datestr, months): ref_year, ref_month = "", "" ref_year_is_leap_year = False aux_date = str(datetime.datetime.strptime(datestr, "%Y-%m-%d")) print(repr(aux_date)) for i_month in range(int(months)): # I add a unit since the months are "numerical quantities", # that is, they are expressed in natural numbers, so I need it # to start from 1 and not from 0 like the iter variable in python i_month = i_month + 1 m1 = re.search( r"(?P<year>\d*)-(?P<month>\d{2})-(?P<startDay>\d{2})", aux_date, re.IGNORECASE, ) if m1: ref_year, ref_month = ( str(m1.groups()[0]).strip(), str(m1.groups()[1]).strip(), ) number_of_days_in_each_month = { "01": "31", "02": "28", "03": "31", "04": "30", "05": "31", "06": "30", "07": "31", "08": "31", "09": "30", "10": "31", "11": "30", "12": "31", } n_days_in_this_i_month = number_of_days_in_each_month[ref_month] print(n_days_in_this_i_month) # nro days to increment in each i month iteration if ( int(ref_year) % 4 == 0 and int(ref_year) % 100 == 0 and int(ref_year) % 400 != 0 ): ref_year_is_leap_year = True # divisible entre 4 y 10 y no entre 400, para determinar que sea un año bisciesto if ref_year_is_leap_year == True and ref_month == "02": n_days_in_this_i_month = str(int(n_days_in_this_i_month) + 1) # 28 --> 29 aux_date = ( datetime.datetime.strptime(datestr, "%Y-%m-%d") + datetime.timedelta(days=int(n_days_in_this_i_month)) ).strftime("%Y-%m-%d") print(repr(aux_date)) return aux_date print(repr(add_months("2022-12-30", "3")))
优化后的函数代码
def add_months(datestr, months): ref_year, ref_month = "", "" ref_year_is_leap_year = False #condicional booleano, cuya logica binaria intenta establecer si es o no bisiesto el año tomado como referencia aux_date = datetime.datetime.strptime(datestr, "%Y-%m-%d") for i_month in range(int(months)): i_month = i_month + 1 # I add a unit since the months are "numerical quantities", that is, they are expressed in natural numbers, so I need it to start from 1 and not from 0 like the iter variable in python m1 = re.search( r"(?P<year>\d*)-(?P<month>\d{2})-(?P<startDay>\d{2})", str(aux_date), re.IGNORECASE, ) if m1: ref_year, ref_month = ( str(m1.groups()[0]).strip(), str( int(m1.groups()[1]) + 1).strip(), ) if( len(ref_month) == 1 ): ref_month = "0" + ref_month if( int(ref_month) > 12 ): ref_month = "01" print(ref_month) number_of_days_in_each_month = { "01": "31", "02": "28", "03": "31", "04": "30", "05": "31", "06": "30", "07": "31", "08": "31", "09": "30", "10": "31", "11": "30", "12": "31", } n_days_in_this_i_month = number_of_days_in_each_month[ref_month] if ( int(ref_year) % 4 == 0 and int(ref_year) % 100 != 0 ) or ( int(ref_year) % 400 == 0 ): ref_year_is_leap_year = True ref_year_is_leap_year = True # divisible entre 4 y 10 y no entre 400, para determinar que sea un año bisciesto if ref_year_is_leap_year == True and ref_month == "02": n_days_in_this_i_month = str(int(n_days_in_this_i_month) + 1) # 28 --> 29 print(n_days_in_this_i_month) # nro days to increment in each i month iteration aux_date = aux_date + datetime.timedelta(days=int(n_days_in_this_i_month)) return datetime.datetime.strftime(aux_date, "%Y-%m-%d")
问题解答
1. 原函数中aux_date无法递增的根本原因
核心问题出在循环内更新aux_date的代码:
aux_date = ( datetime.datetime.strptime(datestr, "%Y-%m-%d") + datetime.timedelta(days=int(n_days_in_this_i_month)) ).strftime("%Y-%m-%d")
每次循环都基于原始输入的datestr解析出初始日期,再加上当月天数,而不是用上一次循环已经更新后的aux_date进行累加。这就导致每次循环得到的都是“原始日期+1个月”的结果,完全没有增量迭代的效果,自然会出现日期停滞的问题。
此外原函数还有两处次要错误:
- 闰年判断逻辑写反:当前条件判断的是平年的情况,却错误设置了
ref_year_is_leap_year = True。 - 把
aux_date转成字符串后用正则解析,既冗余又容易出错,datetime对象本身可直接获取年、月、日属性。
2. 更新后的函数是否正确实现了日期增量累加?
更新后的函数修复了核心的累加问题,但仍存在多处bug和逻辑缺陷,没有完全正确实现需求:
已修复的部分
aux_date改为存储datetime对象,循环中用aux_date = aux_date + datetime.timedelta(days=int(n_days_in_this_i_month))实现了基于当前日期的累加,解决了停滞问题。- 修正了闰年判断的逻辑条件,现在能正确识别闰年。
仍存在的问题
- 语法错误:闰年判断行重复写了
ref_year_is_leap_year = True,会直接抛出语法错误,无法运行。 - 月份处理逻辑错误:
- 解析
aux_date时把当前月份加1作为ref_month,但当月份是12时,加1变成13,后续虽设为01,但未同步更新年份,导致闰年判断仍使用旧年份,会出现错误(比如2022-12累加后进入2023年,但ref_year还是2022)。 - 完全没必要用正则解析datetime字符串,直接用
aux_date.year、aux_date.month就能获取准确的年、月信息,正则解析既冗余又容易引入格式错误。
- 解析
- 冗余代码:
i_month = i_month + 1完全没用,循环次数由range(int(months))控制,该变量未参与任何逻辑计算。 - 语义偏差:通过累加每个月的天数来实现“加N个月”,和实际业务中“加N个月”的语义不符。比如原始日期是2023-01-31,加1个月按函数逻辑会加31天得到2023-03-03,但实际期望通常是2023-02-28(非闰年),这种月底场景会出现不符合预期的结果。
内容的提问来源于stack exchange,提问作者Matt095
相关产品推荐
相关产品推荐

