为何格式化显示相同的Python datetime对象比较不相等?
问题描述
我正在编写Python3脚本,按5分钟增量处理数据。通过一段代码可以把任意datetime对象向下取整到最近的5分钟节点(比如:00、:05、:10这类),而且不能用pandas。现在要比较取整后的datetime和其他datetime对象,遇到了问题。
测试代码
import sys from datetime import datetime from datetime import timedelta def roundDownDateTime(dt): # 参数: # dt datetime对象 delta = timedelta(minutes=1) * (dt.minute % 5) return dt - delta def testAlarm(testDate): # 参数: # testDate datetime对象 currDate = roundDownDateTime(datetime.now()) # currDate是向下取整到5分钟的DateTime对象 print("currDate: "+currDate.strftime("%Y%m%d%H%M")) print("testDate: "+testDate.strftime("%Y%m%d%H%M")) if currDate == testDate: print("ALARM!!!!") def main(): testDate = datetime.strptime(sys.argv[1], "%Y%m%d%H%M") testAlarm(testDate) if __name__ == "__main__": main()
代码执行逻辑
- main()函数接收命令行输入的字符串,转换成
%Y%m%d%H%M格式的datetime对象 - 将该datetime向下取整到最近的5分钟增量节点
- 在testAlarm()中,把它和同样向下取整到5分钟增量的当前时间(格式为
%Y%m%d%H%M)做比较 - 如果两者匹配,应该输出"ALARM!!!!"
实际输出(Ubuntu机器)
me@unbuntu1$ date Tue Jan 17 14:27:41 UTC 2023 me@unbuntu1$ me@unbuntu1$ python3 toy04.py 202301171425 currDate: 202301171425 testDate: 202301171425 me@unbuntu1$
问题
虽然取整后的日期和当前时间取整版本格式化显示完全一样,但if currDate == testDate:的判断结果还是False。我怀疑取整后的datetime还残留秒或微秒,于是修改了roundDownDateTime函数:
def roundDownDateTime(dt): # 参数: # dt DateTime对象 delta = timedelta(minutes=1) * (dt.minute % 5) dt = dt - delta dt.replace(second=0, microsecond=0) return dt
但修改后没有任何变化,输出还是一样。我需要实现取整后的datetime对象的相等性比较,请问我忽略了什么?roundDownDateTime函数有问题吗?
解答
问题出在两个关键点:
- datetime对象是不可变类型:
dt.replace(second=0, microsecond=0)不会修改原对象,而是返回一个新的datetime实例。你之前的代码只是调用了replace,但没有把返回值赋值给dt,所以原dt仍保留着秒和微秒。 - 两个datetime对象的实际属性不一致:你传入的
testDate是通过strptime生成的,秒和微秒默认是0;但currDate从datetime.now()取整后,只是减去了分钟的delta,秒和微秒还是保留着原时间的数值(比如测试时的14:27:41,减去2分钟delta后是14:25:41,秒仍为41),所以两个对象实际并不相等,只是格式化后隐藏了秒和微秒。
修正后的roundDownDateTime函数应该接收replace的返回值:
def roundDownDateTime(dt): # 参数: # dt datetime对象 delta = timedelta(minutes=1) * (dt.minute % 5) dt = dt - delta # 接收replace返回的新对象,清除秒和微秒 dt = dt.replace(second=0, microsecond=0) return dt
或者更简洁的写法,直接一步完成取整和清除秒微秒:
def roundDownDateTime(dt): return dt.replace( minute=(dt.minute // 5) * 5, second=0, microsecond=0 )
这样处理后,两个datetime对象的年、月、日、时、分、秒、微秒完全一致,相等性判断会正常返回True,触发"ALARM!!!!"输出。
内容的提问来源于stack exchange,提问作者Pete
相关产品推荐
相关产品推荐

