Python判断给定日期是否恰好为一个月前及边界问题修复方案
自然月前推校验规则实现
需求说明
判断给定日期是否恰好是今日的一个月前,按自然月对齐日度,而非间隔固定30天,例如今日为2021年11月1日,则一个月前应为2021年10月1日。
原有代码问题
原有实现逻辑如下:
today = fields.Date.from_string(fields.Date.today()) if today.month == 1: one_month_ago = today.replace(year=today.year - 1, month=12) else: extra_days = 0 while True: try: one_month_ago = today.replace(month=today.month - 1, day=today.day - extra_days) break except ValueError: extra_days += 1 if one_month_ago == given_date: # do something else: # do something
该代码仅覆盖了常规场景,存在两类边界问题:
- 给定日期为2021年3月31日、今日为2021年4月30日时,原有逻辑从4月30日前推只能得到3月30日,无法匹配3月31日的给定日期
- 1月29日-31日对应2月无对应日期的场景下,判断结果不符合预期
优化实现
方案1:依赖dateutil库(推荐)
直接使用时间偏移工具类同时覆盖正反校验逻辑,代码简洁易维护:
from dateutil.relativedelta import relativedelta today = fields.Date.today() # 同时覆盖常规场景和月末边界场景 is_match = (today + relativedelta(months=-1) == given_date) or (given_date + relativedelta(months=1) == today) if is_match: # 符合条件的业务逻辑 pass else: # 不符合条件的业务逻辑 pass
方案2:无第三方依赖实现
如果不能引入额外依赖,可以通过原生日期操作实现边界场景兼容:
def is_exact_one_month_ago(given_date, today): # 校验常规场景:今日减1个月等于给定日期 prev_year = today.year - 1 if today.month == 1 else today.year prev_month = 12 if today.month == 1 else today.month - 1 try: if today.replace(year=prev_year, month=prev_month) == given_date: return True except ValueError: pass # 校验月末边界场景:给定日期是当月最后一天,且加1个月后的月末等于今日 # 计算给定日期当月最后一天 given_month_last = given_date while True: try: given_month_last = given_month_last.replace(day=given_month_last.day + 1) except ValueError: break # 计算给定日期加1个月后的月末 next_year = given_date.year + 1 if given_date.month == 12 else given_date.year next_month = 1 if given_date.month == 12 else given_date.month + 1 next_month_last = given_date.replace(year=next_year, month=next_month, day=1) while True: try: next_month_last = next_month_last.replace(day=next_month_last.day + 1) except ValueError: break return given_date == given_month_last and next_month_last == today # 调用示例 today = fields.Date.from_string(fields.Date.today()) if is_exact_one_month_ago(given_date, today): # 符合条件的业务逻辑 pass else: # 不符合条件的业务逻辑 pass
内容的提问来源于stack exchange,提问作者Faizan Ahmad
相关产品推荐
相关产品推荐

