Python日期比较代码异常咨询:为何日期从24/07/2020跳至18/08/2020?
嗨Théo,我来帮你解决这两个日期相关的问题!
一、如何测试日期?
测试日期代码的关键是避免依赖不稳定的系统时间,同时覆盖各种边界场景,推荐这些实用方法:
- 固定测试基准日期:别直接用
date.today(),而是手动构造datetime.date对象(比如test_today = date(2020, 7, 14)),这样每次测试的输入都是固定的,结果可重复。 - 验证日期格式转换:针对你用到的
'%d/%m/%Y'这类格式,测试不同日期字符串(比如'31/12/2023'、'01/01/2024')转datetime对象是否正确,尤其注意月末、年初的边界情况。 - 测试比较逻辑的正确性:准备明确的测试用例,比如验证“早于目标日期”“等于目标日期”“晚于目标日期”三种场景下,你的判断逻辑是否符合预期。
- 用工具简化批量测试(可选):如果需要模拟大量不同的当前时间,可以用
freezegun库,它能临时替换系统时间,不用手动改代码里的日期。
二、日期比较代码的异常原因与修复
为什么会出现日期跳变?
你的代码里有个很容易踩的坑:把datetime对象转成字符串后再做比较,但字符串是按字符顺序(字典序)比的,不是日期的实际先后顺序。
举个直观的例子:
- 日期
25/07/2020转成字符串是'25/07/2020',18/08/2020转成字符串是'18/08/2020' - 字典序对比时,第一个字符
'2' > '1',所以字符串层面'25/07/2020' > '18/08/2020',但实际日期18/08明明比25/07晚啊!
回到你的代码逻辑:
你在循环里反复把date_depart、date_retour转成字符串,再和DateStart、DateEnd转成的字符串比较。第一个条件(出发日期≥起始日期)因为是同月份的比较,字符串结果刚好和实际日期一致,但第二个条件(返回日期≥结束日期)就出问题了:
比如当date_depart是25/07/2020时,假设row['duree_sejour']是80天,那date_retour就是13/10/2020,转成字符串是'13/10/2020'。和DateEnd的字符串'24/10/2020'对比时,因为第一个字符'1' < '2',所以判断为不满足条件,不会输出。直到date_depart是18/08/2020,date_retour变成27/10/2020,字符串'27/10/2020'才大于'24/10/2020',满足条件输出——这就是为什么日期会从24/07直接跳到18/08。
修复后的代码
正确的做法是直接用datetime对象比较,完全不需要转成字符串。而且把DateStart和DateEnd转成datetime对象的操作放在循环外,避免重复计算,效率也更高:
from datetime import date, timedelta, datetime DateStart = '16/07/2020' DateEnd = '24/10/2020' # 提前把字符串转成date对象,只做一次 date_start_dt = datetime.strptime(DateStart, '%d/%m/%Y').date() date_end_dt = datetime.strptime(DateEnd, '%d/%m/%Y').date() for i in range(14, 124): date_depart = date.today() + timedelta(days=i) date_retour = date.today() + timedelta(days=(i + row['duree_sejour'])) # 直接用date对象比较,这才是正确的日期先后判断 if date_depart >= date_start_dt and date_retour >= date_end_dt: print("Departure: {}. Back: {}.".format(date_depart.strftime('%d/%m/%Y'), date_retour.strftime('%d/%m/%Y')))
这样修改后,就能正确筛选出符合条件的日期,不会再出现跳变的问题啦!
内容的提问来源于stack exchange,提问作者Theo75

