Python 2.7 Python 2中datetime.datetime计算与Python 3中的计算略有偏差

Python 2.7 Python 2中datetime.datetime计算与Python 3中的计算略有偏差,python-2.7,python-3.x,python-datetime,Python 2.7,Python 3.x,Python Datetime,在将一些代码从Python2移植到Python3的过程中,测试强调了使用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=(

在将一些代码从Python2移植到Python3的过程中,测试强调了使用
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中打印日期的输出:

2016-09-28 04:21:04.844158
Python 3.5.2中打印(日期未来)的输出:

2016-09-28 04:21:04.844157
问题

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))
这仅仅是一微秒的差异,但它让我感到困惑,因为我无法解释它,所以我不知道是否可以用新的Python3行为更新测试结果,或者是否有更复杂的东西在手

可能的潜在客户

也许这是因为Python3如何将0.5舍入到最接近的偶数,而不是像Python2那样向上


更新

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))
(日期最大值-日期最小值)的结果。两种情况下的总秒数(/2
均为0.8441575秒。但是,一旦交给
datetime.timedelta
构造函数:

Python 2:

datetime.timedelta(0, 0, 383843)
Python 3:

datetime.timedelta(0, 0, 383842)

所以在
timedelta
构造函数中发生了一些不稳定的事情

造成这种差异的原因是Python2和Python3的除法行为不同。Python 2使用整数除法,而Python 3使用浮点除法

3/2
在Python2中输出
1
,在Python3中输出
1.5

因此,罪魁祸首是代码的这一部分:
(日期最大值-日期最小值)。总秒数()/2


使用来自未来导入除法的
将导致Python 2使用浮点除法。将
2
更改为
2.0
也将使Python使用浮点除法。

造成这种差异的原因是Python 2和3的除法行为不同。Python 2使用整数除法,而Python 3使用浮点除法

3/2
在Python2中输出
1
,在Python3中输出
1.5

因此,罪魁祸首是代码的这一部分:
(日期最大值-日期最小值)。总秒数()/2


使用来自未来导入除法的
将导致Python 2使用浮点除法。将
2
更改为
2.0
也将使Python使用浮点除法。

来自datetime官方Python 3文档:

如果任何参数是浮点且存在小数微秒,则将合并所有参数剩余的小数微秒,并使用舍入半到偶数分界符将其和舍入到最接近的微秒。如果没有参数是浮点,则转换和规范化过程是精确的(不会丢失任何信息)

用数值替换,我们正在做:

datetime.timedelta(seconds=0.3838425)

然后将浮点值0.38425转换为微秒,即产生383842.5微秒。然后在Python2中将其四舍五入为383843(.5始终向上舍入),在Python3中将其四舍五入为383842(四舍五入为最接近的偶数)。令人误解的是,该值随后以奇数微秒(460315)添加到另一个日期,从而翻转了最终结果的奇偶性

来自datetime官方Python 3文档:

如果任何参数是浮点且存在小数微秒,则将合并所有参数剩余的小数微秒,并使用舍入半到偶数分界符将其和舍入到最接近的微秒。如果没有参数是浮点,则转换和规范化过程是精确的(不会丢失任何信息)

用数值替换,我们正在做:

datetime.timedelta(seconds=0.3838425)

然后将浮点值0.38425转换为微秒,即产生383842.5微秒。然后在Python2中将其四舍五入为383843(.5始终向上舍入),在Python3中将其四舍五入为383842(四舍五入为最接近的偶数)。令人误解的是,该值随后以奇数微秒(460315)添加到另一个日期,从而翻转了最终结果的奇偶性

我尝试将其替换为
/2.0
,Python 2没有改变其行为。也许如果你把一个浮点传递给
timedelta
,它会对它应用
round
函数,这可以解释不同的行为?我想这可能是事实,如果你“手工”计算,
(date\u max-date\u min)。total_seconds()/2
给出844157.5微秒。。。这看起来很可疑,对吗?@ValentinB。它使用
mod
的浮点版本将其转换为
int
:如果
isinstance(seconds,float):secondsfrac,seconds=\u math.modf(seconds)assert seconds==int(seconds)seconds=int(seconds)secondsfrac+=dayssecondsfrac assert abs(secondsfrac)但在我的理论中,有些东西是不符合逻辑的:如果这是一个取整问题,Python 3将取整到偶数844158,而不是奇数844157。。。但是在Python 2中将该除法更改为浮点除法不会产生与Python 3相同的结果,因为它已经是浮点除法(分子以秒为单位,因此它已经是十进制的)。@ValentinB。“问题”肯定在
timedelta
对象的创建中
(date\u max-date\u min)。在Python 2和Python 3中,total\u seconds()/2
实际返回
0.383838425
print(datetime.timedelta(seconds=seconds))
在Python3中返回
0:00:00.383842
,在Python2中返回
0:00:00.383843
。我尝试将其替换为
/2.0
,Python2没有改变其行为。也许如果你把一个浮点传递给
timedelta
,它会对它应用
round
函数,这可以解释不同的行为?我想这可能是事实,如果你“手工”计算,
(date\u max-date\u min)。total_seconds()/2
给出844157.5微秒。。。这看起来很可疑,对吗?@ValentinB。它使用
mod
的浮点版本将其转换为
int
:if
isinstance(秒,浮点):秒