Python计算年龄的时间,第二部分:时区

22

继续上一个问题 Python time to age,我现在遇到了一个与时区有关的问题,结果发现它并不总是"+0200"。 因此,当strptime尝试将其解析为这样的时间戳时,会引发异常。

我考虑过使用 [:-6] 或其他方式来去掉 +0200,但是否有一种真正的方法可以通过 strptime 来完成呢?

我正在使用 Python 2.5.2 版本,如果有影响的话。

>>> from datetime import datetime
>>> fmt = "%a, %d %b %Y %H:%M:%S +0200"
>>> datetime.strptime("Tue, 22 Jul 2008 08:17:41 +0200", fmt)
datetime.datetime(2008, 7, 22, 8, 17, 41)
>>> datetime.strptime("Tue, 22 Jul 2008 08:17:41 +0300", fmt)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/lib/python2.5/_strptime.py", line 330, in strptime
    (data_string, format))
ValueError: time data did not match format:  data=Tue, 22 Jul 2008 08:17:41 +0300  fmt=%a, %d %b %Y %H:%M:%S +0200
5个回答

40

有没有用strptime实现的真正方法?

没有,但由于您的格式似乎是RFC822日期格式,因此您可以使用email库更轻松地读取它:

>>> import email.utils
>>> email.utils.parsedate_tz('Tue, 22 Jul 2008 08:17:41 +0200')
(2008, 7, 22, 8, 17, 41, 0, 1, 0, 7200)

(7200 = 相对于UTC的时区偏移量(以秒为单位))


有趣,但是我可以简单地计算两个日期之间的差异吗? - Ashy
6
如果您正在使用 datetime,可以使用结果元组的前六个值创建一个 datetime 对象,然后通过减去最后一个值的差来补偿时区,例如“datetime.datetime(*a [:6]) -datetime.timedelta(seconds = a [-1])”。然后按照上一个问题的方式比较 datetimes。 - bobince
2
如果你正在使用普通的 'time',请使用mktime()将除最后一个值外的所有元素转换为数字时间戳,然后减去最后一个值。请注意,mktime会根据您本地服务器的时区提供时间戳,而不是UTC,但是如果您仅比较两个时间戳,则这并不重要。 - bobince
2
有趣的是,电子邮件模块实际上比时间日期模块本身更容易完成工作! - erickrf
@Ashy:要找出时间差,你可以将时间元组转换为自纪元以来的秒数:ts = mktime_tz(parsedate_tz(date_str)) - jfs
真是一团糟。Python开发者,要简化,不要“复杂化”,否则你们最终会像PHP一样。 - Armen Michaeli

28

自2.6版本以后引入。

对于一个naive对象,%z和%Z格式码将被替换为空字符串。

看起来这只在>=2.6中实现,并且我认为您必须手动解析它。

我看不到另一个解决方案,除了删除时区数据:

from datetime import timedelta,datetime
try:
    offset = int("Tue, 22 Jul 2008 08:17:41 +0300"[-5:])
except:
    print "Error"

delta = timedelta(hours = offset / 100)

fmt = "%a, %d %b %Y %H:%M:%S"
time = datetime.strptime("Tue, 22 Jul 2008 08:17:41 +0200"[:-6], fmt)
time -= delta

再次感谢gs和David :) 我想我只能把结尾删掉,不想为此依赖2.6。 - Ashy
不支持委内瑞拉这样的时区:-0430 - chachan
@chachan:但是可以轻松地进行适应。 - Georg Schölly

18
你可以使用非常有用的 dateutil 库:
from datetime import datetime
from dateutil.parser import parse

dt = parse("Tue, 22 Jul 2008 08:17:41 +0200")
## datetime.datetime(2008, 7, 22, 8, 17, 41, tzinfo=tzoffset(None, 7200)) <- dt

print dt
2008-07-22 08:17:41+02:00

我之前不知道这个解决方案,刚刚测试了一下:真的很棒! - user1151446

1
据我所知,strptime()不识别数字时区代码。如果您知道字符串总是以这种形式的时区规范结尾(+或-后跟4个数字),那么将其截掉并手动解析似乎是完全合理的事情。

0

看起来 %Z 对应的是时区名称,而不是偏移量。

例如,给定:

>>> format = '%a, %d %b %Y %H:%M:%S %Z'

我可以解析:

>>> datetime.datetime.strptime('Tue, 22 Jul 2008 08:17:41 GMT', format)
datetime.datetime(2008, 7, 22, 8, 17, 41)

虽然看起来它似乎与时区无关,但仅仅观察其存在和有效性:

>>> datetime.datetime.strptime('Tue, 22 Jul 2008 08:17:41 NZDT', format)
datetime.datetime(2008, 7, 22, 8, 17, 41)

我想,如果你愿意的话,你可以找到一个偏移量到名称的映射,将你的输入转换,然后解析它。不过,直接截断你的输入可能会更简单。


%Z 是时区的名称,%z 表示小时数。 - Georg Schölly
6
如果我尝试在strptime中使用%z,我会得到以下错误: ValueError: 在格式“%z”中,“z”是一个无效的指令。 - John Fouhy

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接