You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何格式化显示相同的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函数有问题吗?


解答

问题出在两个关键点:

  1. datetime对象是不可变类型:dt.replace(second=0, microsecond=0)不会修改原对象,而是返回一个新的datetime实例。你之前的代码只是调用了replace,但没有把返回值赋值给dt,所以原dt仍保留着秒和微秒。
  2. 两个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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.04 09:40:31