Python 中 datetime.strptime() 函数的时区指令 '%z' 不可用。

21

使用 datetime.strptime() 的 '%z' 模式

我有一个字符串表示日期,我可以很好地解析它并将其转换为干净的 datetime 对象:

date = "[24/Aug/2014:17:57:26"
dt = datetime.strptime(date, "[%d/%b/%Y:%H:%M:%S")  

除了使用%z模式来捕获此处指定的时区,我不能获取整个日期字符串。

date_tz = 24/Aug/2014:17:57:26 +0200
dt = datetime.strptime(date, "[%d/%b/%Y:%H:%M:%S %z]")
>>> ValueError: 'z' is a bad directive in format '[%d/%b/%Y:%H:%M:%S %z]'

因为就像这个bug报告所说的:

strftime()是按平台实现的

我要强调的是,使用简单的tzinfo指令'%Z'并不会出现这样的问题。

解决方法:将tzinfo字符串转换为tzinfo对象

我可以通过使用dateutil模块中建议的方法,将GST时间格式的字符串转换为tzinfo对象,并然后将其插入到datetime对象中(点击此处)来实现以下解决方法。

问题:如何使%z在我的平台上可用?

但因为我显然需要%z模式来进行进一步的项目,所以我想找到一个避免使用外部模块完成这个简单任务的解决方案。 你能给我提供一些阅读材料吗?我想新版的Python(我用的是2.7)应该可以处理它,但我不想因为这个小但关键的细节而现在更改我的版本。

[编辑]

好吧,看到评论让我重新表述我的问题:如何使用strptime()解析电子邮件时区指示符,而不必了解本地时间?


2
如果Python依赖的底层C库不支持它,那么你将无法获得它。 - Mark Ransom
那么我想象一下,我没有其他选择,只能每次使用这种丑陋而低效的解决方法? - c24b
我不知道有任何方法可以做到这一点,而且我相信这个问题以前已经被问过了。 - Mark Ransom
关于时区问题,您可能需要查看 pytz -> http://pytz.sourceforge.net/ - Gohn67
pytz不会将形如“+0400”的字符串格式转换为tzinfo对象。我需要它不考虑我的语言环境,而是考虑输入的字符串。 - c24b
1
与https://dev59.com/p4Dba4cB1Zd3GeqPAihD相关的内容。 - wanghq
3个回答

28

strptime()是用纯Python实现的。与strftime()不同的是,它[支持哪些指令]不依赖于平台。自Python 3.2以来,支持%z

>>> from datetime import datetime
>>> datetime.strptime('24/Aug/2014:17:57:26 +0200', '%d/%b/%Y:%H:%M:%S %z')
datetime.datetime(2014, 8, 24, 17, 57, 26, tzinfo=datetime.timezone(datetime.timedelta(0, 7200)))

如何使用strptime()解析电子邮件时区指示符而不了解本地时间?
Python 2.7没有具体的时区实现。您可以轻松实现UTC偏移解析,请参见如何在python中解析带有-0400时区字符串的日期?

注意:%z 只匹配 GMT、UTC 和 time.tzname。这是一个限制:https://bugs.python.org/issue22377 - xtreak
5
不要混淆 %Z(时区缩写)和 %z(数字偏移量)。 - jfs
@jfs 谢谢你发现了它 :) - xtreak

15

继续@j-f-sebastians的回答,这里是Python 2.7的修复方法:

不要使用:

datetime.strptime(t,'%Y-%m-%dT%H:%M %z')

使用 timedelta 来考虑时区,像这样:

from datetime import datetime,timedelta
def dt_parse(t):
    ret = datetime.strptime(t[0:16],'%Y-%m-%dT%H:%M')
    if t[17]=='+':
       ret-=timedelta(hours=int(t[18:20]),minutes=int(t[20:]))
    elif t[17]=='-':
       ret+=timedelta(hours=int(t[18:20]),minutes=int(t[20:]))
    return ret

print(dt_parse('2017-01-12T14:12 -0530'))

应该不是 timedelta(hours=int(t[19:22]),minutes=int(t[23:])) 吗? - guilhermecgs
1
如果意图是返回相应的UTC时间,则符号是正确的:“本地时间= UTC时间+ UTC偏移量”,因此,给定本地时间和偏移量,要获取UTC时间:“UTC时间=本地时间- UTC偏移量”。例如,“18:00 +0200”对应于16:00 UTC。为了消除歧义,返回时区感知日期时间对象:return utc_dt.replace(tzinfo=DT.timezone.utc) - jfs

2

Uri的回答非常好,救了我的命,但是当你有USE_TZ = True时,你需要注意时间,以避免出现警告"RuntimeWarning: DateTimeField",最好在返回值中添加utc。

import pytz
from datetime import datetime, timedelta
def dt_parse(t):
    ret = datetime.strptime(t[0:19],'%Y-%m-%dT%H:%M:%S')
    if t[23]=='+':
        ret-=timedelta(hours=int(t[24:26]), minutes=int(t[27:]))
    elif t[23]=='-':
        ret+=timedelta(hours=int(t[24:26]), minutes=int(t[27:]))
    return ret.replace(tzinfo=pytz.UTC)

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