如何基于月日字符串构造Python下一次出现的datetime对象
实现基于月日字符串的下一次出现日期构造函数
需求描述
有一个仅包含月日的字符串(格式为"%m/%d",例如"12/25"),需要构造一个相对于今天的该日期下一次出现的datetime对象。理想的调用形式如下:
datetime.next_strptime("12/25", "%m/%d") # 若当前日期早于2023-12-25,则返回2023-12-25的datetime对象
现有方案的不足
自己编写的基础代码如下:
from datetime import datetime from dateutil.relativedelta import relativedelta # 因缺少年份,初始为1900-12-25 date = datetime.strptime("12/25", "%m/%d") # 替换为当前年份,即2023-12-25 date = date.replace(year=datetime.today().year) # 如果今天已过2023-12-25,则年份加1 if date < datetime.today(): date = date + relativedelta(years=1)
但这个方案存在两个明显问题:
- 代码步骤拆分繁琐,冗余度高
- 无法处理闰年日期(例如
"2/29"):strptime默认使用1900年(非闰年)解析该字符串会直接抛出异常,即使替换为当前年份,若当前年份非闰年也会报错。
稳健的实现方案
下面的实现可以处理包括闰年在内的所有边缘情况,逻辑更简洁:
from datetime import datetime from dateutil.relativedelta import relativedelta def next_strptime(month_day_str, format_str="%m/%d"): today = datetime.today() current_year = today.year # 拆分月日,避免用strptime解析闰年日期时的初始异常 month, day = map(int, month_day_str.split('/')) # 尝试构造当前年份的目标日期 try: target_date = datetime(current_year, month, day) except ValueError: # 当前年份不是闰年,处理2/29的情况,直接找下一个闰年的2/29 target_date = None year = current_year + 1 while not target_date: try: target_date = datetime(year, month, day) except ValueError: year += 1 # 判断目标日期是否已过,已过则往后推一年(同时处理闰年情况) if target_date < today: try: target_date = datetime(target_date.year + 1, month, day) except ValueError: # 原日期是2/29,下一年非闰年,继续找下一个闰年 year = target_date.year + 2 while True: try: target_date = datetime(year, month, day) break except ValueError: year += 1 return target_date
功能验证
- 若当前日期是2023-10-01,调用
next_strptime("12/25")返回2023-12-25 00:00:00 - 若当前日期是2023-12-30,调用
next_strptime("12/25")返回2024-12-25 00:00:00 - 若当前日期是2023-03-01,调用
next_strptime("2/29")返回2024-02-29 00:00:00 - 若当前日期是2024-03-01,调用
next_strptime("2/29")返回2028-02-29 00:00:00
内容的提问来源于stack exchange,提问作者Nathan
相关产品推荐
相关产品推荐

