Python时间库:如何使用strptime和strftime保存dst

时间:2016-03-25 04:15:23

标签: python time timezone utc dst

我需要以可读格式存储时间戳,然后我需要将其转换为纪元以进行比较。

我试过这样做:

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秒的Delta,我得到3601(1小时1秒),一致。

进一步调查,似乎当我执行time.gmtime()时,struct的tm_isdst = 0,而来自timestamp1 string的转换结构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以保持简单/缩短;我仍然可以这样做。

1 个答案:

答案 0 :(得分:2)

下面首先说明问题,然后是两个可能的解决方案,一个使用time,另一个使用datetime

问题解释

问题在于OP在问题中提出的观察结果:tm_isdst=-1tm_isdst是一个标志,用于确定夏令时是否生效(有关详细信息,请参阅https://docs.python.org/2/library/time.html#time.struct_time)。 具体而言,给定OP的时间字符串格式(符合RFC 2822 Internet电子邮件标准),[time.strptime] 4不存储有关时区的信息,即{ {1}}。因此,当根据字符串+0000中的信息再次创建struct_time时,即未知。在进行计算时如何填写该信息的猜测基于本地系统。例如,就好像系统引用北美时间夏令时有效,tm_isdst=-1已设置。

tm_isdst

的解决方案

如果您只想使用time包,那么直接解析信息的最简单方法是指定时间以UTC为单位,从而将time添加到格式中。请注意,%Z未提供在time中存储有关时区的信息的方法。因此,它不会打印与变量中保存的时间相关联的实际时区。从系统检索时区。因此,无法直接对time.strftime使用相同的格式。用于编写和读取字符串的代码部分如下所示:

struct_time

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)

的解决方案

另一种解决方案涉及使用直接支持时区的datetimedateutil包,代码可以是(假设保留时区信息是必需的):

datetime

有一些方面需要注意:

  • 调用utcnow后,时区未设置,因为它是一个天真的UTC日期时间。如果不需要有关UTC的信息,则可以删除两次设置时区的两条线,结果也是相同的,因为没有关于夏令时的猜测。

  • 由于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() 未正确解析,因此无法使用datetime.strptime。如果字符串包含有关时区的信息,则应使用%z

  • 可以直接执行parser的两个实例的差异,并将得到的增量转换为秒。

  • 如果需要从纪元开始以秒为单位获得时间,则应进行显式计算,因为没有直接函数在datetime中自动执行此操作(在答案时) )。代码下方,例如datetime

    utc_time2
  • datetime.resolution,即两个不相等epoch_time = datetime(1970,1,1) epoch2 = (utc_time2 - epoch_time).total_seconds() 个对象之间可能存在的最小差异。这导致差异达到分辨率。