我在Python中使用datetime时遇到了一些麻烦。我尝试将日期时间转换为时间戳然后再返回,无论我如何尝试最终结果都不一样。我总是以日期时间(2014年,1月,30年,23年,59年,40年,1998年)结束。
import datetime
a = datetime.datetime.timestamp(datetime.datetime(2014, 1, 30, 23, 59, 40, 1999))
b = datetime.datetime.fromtimestamp(a)
print(b)
答案 0 :(得分:3)
最后一个数字是微秒......内部是否准确?让我们来看看。
counter={}
for i in range(0,1000000,43):
# fuzz up some random-ish dates
d = datetime.datetime( 1990+(i%20), 1+(i%12), 1+(i%28), i%24, i%60, i%60, i)
ts=datetime.datetime.timestamp( d)
b = b=datetime.datetime.fromtimestamp(ts)
msdif=d.microsecond-b.microsecond
if msdif in counter:
counter[msdif] += 1
else:
counter[msdif]=1
assert b.day==d.day and b.hour==d.hour and b.minute==d.minute and b.second=d.second
>>>
>>> counter
{1: 23256}
>>>
我确实相信你在日期时间库中发现了一个一微秒的错误,除非规范中存在不正常的内容。
(我期待零点差异,反映出某种舍入错误)
答案 1 :(得分:3)
这是一个众所周知的Python 3.4 issue:
>>> from datetime import datetime
>>> local = datetime(2014, 1, 30, 23, 59, 40, 1999)
>>> datetime.fromtimestamp(local.timestamp())
datetime.datetime(2014, 1, 30, 23, 59, 40, 1998)
注意:微秒消失了。 .timestamp()
已经返回略小于1999
微秒的结果:
>>> from decimal import Decimal
>>> local.timestamp()
1391126380.001999
>>> Decimal(local.timestamp())
Decimal('1391126380.0019989013671875')
The rounding is fixed in the next 3.4, 3.5, 3.6 releases:
>>> from datetime import datetime
>>> local = datetime(2014, 1, 30, 23, 59, 40, 1999)
>>> datetime.fromtimestamp(local.timestamp())
datetime.datetime(2014, 1, 30, 23, 59, 40, 1999)
要解决此问题,您可以使用显式公式:
>>> from datetime import datetime, timedelta
>>> local = datetime(2014, 1, 30, 23, 59, 40, 1999)
>>> datetime.utcfromtimestamp(local.timestamp())
datetime.datetime(2014, 1, 30, 23, 59, 40, 1998) # UTC time
>>> datetime(1970, 1, 1) + timedelta(seconds=local.timestamp())
datetime.datetime(2014, 1, 30, 23, 59, 40, 1999) # UTC time
注意:所有示例中的输入都是本地时间,但结果是最后一次的UTC时间。
答案 2 :(得分:1)
很少有带小数的浮点数可以精确地表示为二进制浮点数;通常会有一些非常小的错误。有时它会小于所需的数字,有时它会更大,但它应该总是非常接近。您的示例的确切值为1391147980.0019989013671875
,该值在您指定的0.1微秒内。
从浮点timestamp
转换回datetime
应该使用舍入来确保往返转换提供与原始值相同的值。如J.F. Sebastian所述,这是作为Python 3.4的错误输入的;它声称在以后的版本中得到修复,但它仍然存在于Python 3.5.0中,使用与问题中给出的相同的值。运行类似于nigel222的测试,显示精确匹配与低于1微秒的结果之间几乎有50/50的分割。
由于您知道原始值是整数微秒,因此您可以添加一个偏移量,以确保二进制浮点值始终高于十进制值,同时仍然足够小,以至于它不会影响结果适当圆润。由于舍入应在0.5微秒发生,理想偏移量将是其一半,或0.25微秒。
以下是Python 3.5.0中的结果:
>>> a = datetime.datetime.timestamp(datetime.datetime(2014, 1, 30, 23, 59, 40, 1999))
>>> b = datetime.datetime.fromtimestamp(a)
>>> a
1391147980.001999
>>> b
datetime.datetime(2014, 1, 30, 23, 59, 40, 1998)
>>> b = datetime.datetime.fromtimestamp(a + 0.00000025)
>>> b
datetime.datetime(2014, 1, 30, 23, 59, 40, 1999)
>>> counter={}
>>> for i in range(0,1000000):
# fuzz up some random-ish dates
d = datetime.datetime(1990+(i%20), 1+(i%12), 1+(i%28), i%24, i%60, i%60, i)
ts = datetime.datetime.timestamp(d)
b = datetime.datetime.fromtimestamp(ts + 0.00000025)
msdif = d.microsecond - b.microsecond
if msdif in counter:
counter[msdif] += 1
else:
counter[msdif]=1
assert b.day==d.day and b.hour==d.hour and b.minute==d.minute and b.second==d.second
>>> counter
{0: 1000000}