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



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

我试过这样做:

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,而从时间戳p1字符串转换的结构t1的tm_isdst=-1。

如何确保isdst保留为0。我想这可能就是问题所在。

或者有没有更好的方法以人类可读的格式(UTC)记录时间,并且能够正确地转换回epoch进行时间差异计算?

更新:昨晚做了更多的研究后,我改用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以保持它的简单/简短;我仍然可以那样做。

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

问题解释

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

time解决方案

如果只想使用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解决方案

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

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的猜测。

  • 由于%z未正确解析,因此无法使用datetime.strptime。如果字符串包含有关时区的信息,则应使用parser

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

  • 如果有必要获得自epoch以来的时间(以秒为单位),则应进行显式计算,因为在datetime中(在回答时)没有直接函数自动进行计算。代码下方,例如utc_time2:

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

相关内容

  • 没有找到相关文章

最新更新