Python 2 和 3 中的 datetime.datetime 计算略有偏差
Slight deviation between datetime.datetime calculations in Python 2 and 3
在将一些代码从 Python 2 移植到 Python 3 时,测试突出显示了使用 datetime.datetime
计算日期时的数值回归,我很难解释。
如何重现
date_max = datetime.datetime(2016, 9, 28, 4, 21, 5, 228000)
date_min = datetime.datetime(2016, 9, 28, 4, 21, 4, 460315)
date_futur = date_min + datetime.timedelta(seconds=((date_max - date_min).total_seconds() / 2))
输出
Python 2.7.12 中 print date_futur
的输出:
2016-09-28 04:21:04.844158
Python 3.5.2 中 print(date_futur)
的输出:
2016-09-28 04:21:04.844157
问题
这只是一微秒的差异,但它让我很烦恼,因为我无法解释它,所以我不知道我是否可以用新的 Python 3 行为更新我的测试结果,或者是否有更复杂的东西在眼前。
可能领先
可能是因为 Python 3 如何将 0.5 舍入到最接近的偶数,而不是像 Python 2 ?
更新
两种情况下 (date_max - date_min).total_seconds() / 2
的结果都是 0.8441575 秒。但是,一旦交给 datetime.timedelta
构造函数:
Python 2:
datetime.timedelta(0, 0, 383843)
Python 3:
datetime.timedelta(0, 0, 383842)
所以 timedelta
构造函数中发生了一些奇怪的事情!
造成这种差异的原因是 Python 2 和 3 的除法行为不同。Python 2 使用整数除法,而 Python 3 使用浮点数除法。
3 / 2
在 Python 2 中输出 1
,在 Python 3 中输出 1.5
。
所以罪魁祸首是你的这部分代码:
(date_max - date_min).total_seconds() / 2
使用from __future__ import division
将导致Python 2 使用浮点除法。将 2
更改为 2.0
也会使 Python 使用浮点除法。
来自datetime官方Python3文档:
If any argument is a float and there are fractional microseconds, the fractional microseconds left over from all arguments are combined and their sum is rounded to the nearest microsecond using round-half-to-even tiebreaker. If no argument is a float, the conversion and normalization processes are exact (no information is lost).
用数值代替,我们在做:
datetime.timedelta(seconds=0.3838425)
然后将浮点值 0.3838425 转换为微秒,得到 383842.5 微秒。然后在 Python 2 中四舍五入为 383843(.5 总是四舍五入),在 Python 3 中四舍五入为 383842(四舍五入到最接近的偶数)。误导的事实是,这个值随后被添加到另一个具有奇数微秒 (460315) 的日期,翻转了最终结果的奇偶校验!
在将一些代码从 Python 2 移植到 Python 3 时,测试突出显示了使用 datetime.datetime
计算日期时的数值回归,我很难解释。
如何重现
date_max = datetime.datetime(2016, 9, 28, 4, 21, 5, 228000)
date_min = datetime.datetime(2016, 9, 28, 4, 21, 4, 460315)
date_futur = date_min + datetime.timedelta(seconds=((date_max - date_min).total_seconds() / 2))
输出
Python 2.7.12 中 print date_futur
的输出:
2016-09-28 04:21:04.844158
Python 3.5.2 中 print(date_futur)
的输出:
2016-09-28 04:21:04.844157
问题
这只是一微秒的差异,但它让我很烦恼,因为我无法解释它,所以我不知道我是否可以用新的 Python 3 行为更新我的测试结果,或者是否有更复杂的东西在眼前。
可能领先
可能是因为 Python 3 如何将 0.5 舍入到最接近的偶数,而不是像 Python 2 ?
更新
两种情况下 (date_max - date_min).total_seconds() / 2
的结果都是 0.8441575 秒。但是,一旦交给 datetime.timedelta
构造函数:
Python 2:
datetime.timedelta(0, 0, 383843)
Python 3:
datetime.timedelta(0, 0, 383842)
所以 timedelta
构造函数中发生了一些奇怪的事情!
造成这种差异的原因是 Python 2 和 3 的除法行为不同。Python 2 使用整数除法,而 Python 3 使用浮点数除法。
3 / 2
在 Python 2 中输出 1
,在 Python 3 中输出 1.5
。
所以罪魁祸首是你的这部分代码:
(date_max - date_min).total_seconds() / 2
使用from __future__ import division
将导致Python 2 使用浮点除法。将 2
更改为 2.0
也会使 Python 使用浮点除法。
来自datetime官方Python3文档:
If any argument is a float and there are fractional microseconds, the fractional microseconds left over from all arguments are combined and their sum is rounded to the nearest microsecond using round-half-to-even tiebreaker. If no argument is a float, the conversion and normalization processes are exact (no information is lost).
用数值代替,我们在做:
datetime.timedelta(seconds=0.3838425)
然后将浮点值 0.3838425 转换为微秒,得到 383842.5 微秒。然后在 Python 2 中四舍五入为 383843(.5 总是四舍五入),在 Python 3 中四舍五入为 383842(四舍五入到最接近的偶数)。误导的事实是,这个值随后被添加到另一个具有奇数微秒 (460315) 的日期,翻转了最终结果的奇偶校验!