我需要以可读格式存储时间戳,稍后我需要将其转换为纪元以供比较。
我试过这样做:
import time
format = '%Y %m %d %H:%M:%S +0000'
timestamp1 = time.strftime(format,time.gmtime()) # '2016 03 25 04:06:22 +0000'
t1 = time.strptime(timestamp1, format) # time.struct_time(..., tm_isdst=-1)
time.sleep(1)
epoch_now = time.mktime(time.gmtime())
epoch_t1 = time.mktime(t1)
print "Delta: %s" % (epoch_now - epoch_t1)
运行此程序,我得到的不是 1 秒的增量,而是 3601(1 小时 1 秒),始终如一。
进一步调查,似乎当我只执行 time.gmtime() 时,该结构具有 tm_isdst=0,而从 timestamp1 字符串转换的结构 t1 具有 tm_isdst=-1。
如何确保 isdst 保留为 0。我认为这可能是这里的问题。
或者是否有更好的方法以人类可读格式 (UTC) 记录时间,并且能够正确转换回纪元以计算时差?
更新: 昨晚做了更多研究后,我转而使用 datetime,因为它在 datetime 对象中保留了更多信息,下面的 albertoql 回答证实了这一点。
这是我现在拥有的:
from datetime import datetime
format = '%Y-%m-%d %H:%M:%S.%f +0000' # +0000 is optional; only for user to see it's UTC
d1 = datetime.utcnow()
timestamp1 = d1.strftime(format)
d1a = datetime.strptime(timestamp1, format)
time.sleep(1)
d2 = datetime.utcnow()
print "Delta: %s" % (d2 - d1a).seconds
我选择不添加 tz 以保持简单/更短;我仍然可以那样 strptime。
最佳答案
下面,首先是对问题的解释,然后是两个可能的解决方案,一个使用 time
, 另一个使用 datetime
.
问题解释
问题在于 OP 在问题中所做的观察:tm_isdst=-1
。 tm_isdst
是一个标志,用于确定夏令时是否有效(更多详细信息请参见 https://docs.python.org/2/library/time.html#time.struct_time)。
具体来说,给定来自 OP 的时间字符串格式(符合 RFC 2822 Internet 电子邮件标准),[time.strptime
] 4不存储时区信息,即+0000
。因此,当 struct_time
根据字符串中的信息再次创建,tm_isdst=-1
,即unknown。计算时如何填写该信息的猜测是基于本地系统的。例如,如果系统指的是北美,那里实行夏令时,则设置 tm_isdst
。
用时间
解决
如果你只想使用time
包,那么,直接解析信息最简单的方法就是指定时间为UTC,从而在格式中添加%Z
。请注意,time
不提供在 struct_time
中存储时区信息的方法。因此,它不会打印与变量中保存的时间相关联的实际时区。时区是从系统中检索的。因此,不可能直接对time.strftime
使用相同的格式。 .写入和读取字符串的代码部分如下所示:
format = '%Y %m %d %H:%M:%S UTC'
format2 = '%Y %m %d %H:%M:%S %Z'
timestamp1 = time.strftime(format, time.gmtime())
t1 = time.strptime(timestamp1, format2)
datetime
的解决方案
另一种解决方案涉及使用 datetime
和 dateutil
直接支持时区的包,代码可以是(假设需要保留时区信息):
from datetime import datetime
from dateutil import tz, parser
import time
time_format = '%Y %m %d %H:%M:%S %z'
utc_zone = tz.gettz('UTC')
utc_time1 = datetime.utcnow()
utc_time1 = utc_time1.replace(tzinfo=utc_zone)
utc_time1_string = utc_time1.strftime(time_format)
utc_time1 = parser.parse(utc_time1_string)
time.sleep(1)
utc_time2 = datetime.utcnow()
utc_time2 = utc_time2.replace(tzinfo=utc_zone)
print "Delta: %s" % (utc_time2 - utc_time1).total_seconds()
有几个方面需要注意:
调用
utcnow
后,时区未设置,因为它是一个天真的 UTC 日期时间。如果不需要有关UTC的信息,可以将两次设置时区的两行都删除,结果是一样的,因为没有猜测DST。不可能使用
datetime.strptime
因为%z
,它没有被正确解析。如果字符串包含有关时区的信息,则应使用parser
。可以直接执行
datetime
的两个实例的差值并将生成的增量转换为秒数。如果需要获取自纪元以来的秒数,则应进行显式计算,因为在
datetime
(当时的答案)。在代码下方,例如utc_time2
:epoch_time = datetime(1970,1,1) epoch2 = (utc_time2 - epoch_time).total_seconds()
datetime.resolution
,即两个不相等的datetime
对象之间的最小可能差异。这会导致取决于分辨率的差异。
关于Python 时间库 : how do I preserve dst with strptime and strftime,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36213899/