将日期时间转换为时间戳,然后再返回

时间:2015-09-24 17:24:11

标签: python datetime python-3.x

我在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)

3 个答案:

答案 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}