Python 计算时间戳和总秒数之间的差异

Python 计算时间戳和总秒数之间的差异,python,python-3.x,datetime,Python,Python 3.x,Datetime,当我在python的datetime中使用两种不同的方法(使用timestamp()或total_seconds())计算两个日期之间的秒数时,我得到了不同的结果。为什么会这样?或者我做错了什么?这是我的意思的一个例子 t1=dt.datetime(1970,6,12,0,0,0) t2=dt.datetime(1970,1,1,0,0,0) print(t1.timestamp()-t2.timestamp()) print((t1-t2).total_seconds()) 我得到的答案是

当我在python的datetime中使用两种不同的方法(使用timestamp()或total_seconds())计算两个日期之间的秒数时,我得到了不同的结果。为什么会这样?或者我做错了什么?这是我的意思的一个例子

t1=dt.datetime(1970,6,12,0,0,0)
t2=dt.datetime(1970,1,1,0,0,0)

print(t1.timestamp()-t2.timestamp())
print((t1-t2).total_seconds())
我得到的答案是: 13993200 13996800.0仅适用于Python 3(3.3版中的新版本)。Python 2中没有这样的方法

在版本3.6中更改:timestamp()方法使用fold属性消除重复间隔期间时间的歧义

注意:没有直接从表示UTC时间的原始datetime实例获取POSIX时间戳的方法。如果应用程序使用此约定,并且系统时区未设置为UTC,则可以通过提供tzinfo=timezone.UTC来获取POSIX时间戳:
timestamp=dt.replace(tzinfo=timezone.utc).timestamp()
或者直接计算时间戳:
timestamp=(dt-datetime(1970,1,1))/timedelta(seconds=1)

夏令时 两个
dt.datetime
对象的减法魔术方法创建了一个与夏令时无关的
dt.timedelta

历元时间戳转换功能将夏令时考虑在内,这解释了3600秒(1小时)的差异

见下面我的侦探帖子。这很有趣


因为这对我来说似乎很有趣,所以我快速地写了一个剧本

这在3.5.4和3.6.2上以相同的输出运行

import datetime as dt

t1 = dt.datetime(1970,1,1,0,0,0)
t2 = dt.datetime(1970,1,1,0,0,0)

for _ in range(365):
    try:
        d1 = t1.timestamp() - t2.timestamp()
        d2 = (t1-t2).total_seconds()
        assert d1 == d2
    except AssertionError as e:
        print(t1, d2-d1)
    t1 += dt.timedelta(days=1)
我得到了这个输出。看起来它是从4月27日开始的,差异始终是一个小时,这意味着跳跃只发生一次(实际上没关系,继续阅读)

我写了第二个剧本:

import datetime as dt

t = dt.datetime(1970,1,1,0,0,0)
sid = 60*60*24

while 1:
    prev = t
    t += dt.timedelta(days=1)
    diff1 = (t-prev).total_seconds()
    diff2 = t.timestamp() - prev.timestamp()
    try:
        assert diff1 == diff2 == sid
    except AssertionError:
        print(diff1, diff2, t, prev)
        exit(1)
输出:

86400.0 82800.0 1970-04-27 00:00:00 1970-04-26 00:00:00
当您移除退出(1)时,输出变得有趣:

86400.0 82800.0 1970-04-27 00:00:00 1970-04-26 00:00:00
86400.0 90000.0 1970-10-26 00:00:00 1970-10-25 00:00:00
86400.0 82800.0 1971-04-26 00:00:00 1971-04-25 00:00:00
86400.0 90000.0 1971-11-01 00:00:00 1971-10-31 00:00:00
86400.0 82800.0 1972-05-01 00:00:00 1972-04-30 00:00:00
86400.0 90000.0 1972-10-30 00:00:00 1972-10-29 00:00:00
86400.0 82800.0 1973-04-30 00:00:00 1973-04-29 00:00:00
86400.0 90000.0 1973-10-29 00:00:00 1973-10-28 00:00:00
86400.0 82800.0 1974-01-07 00:00:00 1974-01-06 00:00:00
86400.0 90000.0 1974-10-28 00:00:00 1974-10-27 00:00:00
86400.0 82800.0 1975-02-24 00:00:00 1975-02-23 00:00:00
86400.0 90000.0 1975-10-27 00:00:00 1975-10-26 00:00:00
86400.0 82800.0 1976-04-26 00:00:00 1976-04-25 00:00:00
86400.0 90000.0 1976-11-01 00:00:00 1976-10-31 00:00:00
...
看起来历元时间戳转换
t.timestamp()-prev.timestamp()
不可靠。更重要的是,它似乎在一个不规则但间隔较长的日期间隔内从负到正振荡一小时(编辑:意识到这些是历史夏令时日期)。如果保持脚本运行,振荡将永远保持,直到到达结束时间:

86400.0 82800.0 9997-03-10 00:00:00 9997-03-09 00:00:00
86400.0 90000.0 9997-11-03 00:00:00 9997-11-02 00:00:00
86400.0 82800.0 9998-03-09 00:00:00 9998-03-08 00:00:00
86400.0 90000.0 9998-11-02 00:00:00 9998-11-01 00:00:00
86400.0 82800.0 9999-03-15 00:00:00 9999-03-14 00:00:00
86400.0 90000.0 9999-11-08 00:00:00 9999-11-07 00:00:00
Traceback (most recent call last):
  File "check.py", line 8, in <module>
    t += dt.timedelta(days=1)
OverflowError: date value out of range
哇,所以在
1970-10-25
1971-04-26
之间没有
AssertionErrors
。这与第二个脚本中发现的振荡相匹配

这真的很奇怪


等一下夏令时

差异是由夏令时引起的。如果您的一个日期落在时区的DST范围内,而另一个不在,那么您的计算结果将出现一个1小时的误差

从1966年到1973年,这就解释了


看起来,当减去两个日期时,它没有注意DST差异
t1-t2
产生
datetime.timedelta(162)
,即162天的差异,即使从技术上讲,小时差异为162*24-1小时(DST跳过的-1原因)<代码>时间戳正在处理这个问题(两个时间戳都是相对于UTC的,因此DST时间戳正确地显示为一个小时之前,因为生成它时跳过了一个小时)。

从我在文档中可以看出,它们应该做同样的事情,但也许我误解了闰秒之类的东西:它向我输出了相同的值,我在Python3.6.1中输入了我用Python3.5.2复制的DateTime。你的python版本是什么?我使用的是python 3.6.0。这种差异发生在t1=dt.datetime(1970,4,26,5,0,0)和t1=dt.datetime(2016,3,25,4,0,0)之间@Chogg:我认为从技术上讲这不是一个bug<代码>时间戳是与历元时间的严格偏移量,正确地说明了DST<代码>日期时间< /代码>减法产生一个精确的增量(两个代码>日期时间< /Calp> s相差162天,并且将δ添加到第二个日期将产生预期的第一个日期),只是中间的DST跳转意味着实际上只有162天减去一个小时的秒。但抽象地说,162天的增量并不总是损失一个小时(有时会增加一个小时,有时不会改变),因此合并它会产生误导。2016年3月/4月左右也存在类似的异常情况。你看到了吗?是的。这是第二个脚本输出的一部分:
86400.0 90000.0 2015-11-02 00:00:00 2015-11-01 00:00:00
86400.0 82800.0 2016-03-14 00:00:00 2016-03-13 00:00:00
86400.0 90000.0 2016-11-07 00:00:00:00 2016-11-06 00:00
@Chogg我刚刚意识到振荡恰好发生在历史日光下节省时间日期!!这就是导致这些异常现象的原因。@Joshurali:嘿。我是。@Chogg:这两个文件都没有直接处理。看看我的答案。时间戳是计算本地时间与历元时间的偏移量(以UTC为单位,因此DST由副作用处理)。datetime减法忽略DST(同一小时的两个日期仅在天而不是小时内不同,即使DST仅对其中一个生效)。没有,没有其他论坛。你可以在跟踪器上提交一个bug,但考虑到这不是一个真正的bug,我最多需要一个文档说明。如果我理解正确,时间戳是相对于我的本地时区计算输入的,因此它会随着夏季时间移动,而减法是不知道时区的,正如上面David Murray所提到的。谢谢你的帮助。
86400.0 82800.0 9997-03-10 00:00:00 9997-03-09 00:00:00
86400.0 90000.0 9997-11-03 00:00:00 9997-11-02 00:00:00
86400.0 82800.0 9998-03-09 00:00:00 9998-03-08 00:00:00
86400.0 90000.0 9998-11-02 00:00:00 9998-11-01 00:00:00
86400.0 82800.0 9999-03-15 00:00:00 9999-03-14 00:00:00
86400.0 90000.0 9999-11-08 00:00:00 9999-11-07 00:00:00
Traceback (most recent call last):
  File "check.py", line 8, in <module>
    t += dt.timedelta(days=1)
OverflowError: date value out of range
...
1970-10-24 00:00:00 3600.0
1970-10-25 00:00:00 3600.0
1971-04-26 00:00:00 3600.0
1971-04-27 00:00:00 3600.0
...