如何将RFC 2822日期/时间解析为Python日期时间?

mil*_*omi 24 python time datetime parsing python-2.5

我有一个RFC 2822指定格式的日期 - 比方说Fri, 15 May 2009 17:58:28 +0000,作为一个字符串.有没有一种快速和/或标准的方法将它作为datetimePython 2.5中的对象?我尝试生成strptime格式字符串,但+0000时区说明符会混淆解析器.

小智 36

问题是parsedate会忽略偏移量.

改为:

from email.utils import parsedate_tz
print parsedate_tz('Fri, 15 May 2009 17:58:28 +0700')
Run Code Online (Sandbox Code Playgroud)

  • 遇到这个问题,发现从 python 3.3 开始,`email.utils` 有一个名为 [`parsedate_to_datetime`](https://python.readthedocs.io/en/latest/library/email.util.html #email.utils.parsedate_to_datetime) 直接输出“datetime”实例。 (2认同)

gon*_*onz 14

我想详细说明以前的答案.email.utils.parsedate并且email.utils.parsedate_tz两者都返回元组,因为OP需要一个datetime.datetime对象,我是为了完整性而添加这些示例:

from email.utils import parsedate
from datetime import datetime
import time

t = parsedate('Sun, 14 Jul 2013 20:14:30 -0000')
d1 = datetime.fromtimestamp(time.mktime(t))
Run Code Online (Sandbox Code Playgroud)

要么:

d2 = datetime.datetime(*t[:6])
Run Code Online (Sandbox Code Playgroud)

请注意,d1d2都天真datetime对象,有没有存放区信息.如果您需要知道日期时间对象,请检查tzinfo datetime()arg.

或者,您可以使用dateutil模块


nos*_*klo 12

from email.utils import parsedate
print parsedate('Fri, 15 May 2009 17:58:28 +0000')
Run Code Online (Sandbox Code Playgroud)

文档.


ebo*_*ebo 8

有一个parsedate功能email.util.它解析所有有效的RFC 2822日期和一些特殊情况.


ere*_*wok 5

看起来Python 3.3继续parsedate_to_datetime在email.utils中有一个新方法来处理中间步骤:

email.utils.parsedate_to_datetime(日期)

format_datetime()的反转.执行与parsedate()相同的功能,但成功时返回datetime.如果输入日期的时区为-0000,则日期时间将是一个天真的日期时间,如果日期符合RFC,则它将表示UTC的时间,但没有指示消息的实际源时区,日期到来从.如果输入日期具有任何其他有效时区偏移量,则日期时间将是具有相应时区tzinfo的有效日期时间.

版本3.3中的新功能.

http://python.readthedocs.org/en/latest/library/email.util.html#email.utils.parsedate_to_datetime


yon*_*ran 5

email.utils.parsedate_tz(date)是要使用的函数。以下是一些变化。

电子邮件日期/时间字符串(RFC 5322RFC 2822RFC 1123)到 unix 时间戳,以浮点秒为单位:

import email.utils
import calendar
def email_time_to_timestamp(s):
    tt = email.utils.parsedate_tz(s)
    if tt is None: return None
    return calendar.timegm(tt) - tt[9]

import time
print(time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime(email_time_to_timestamp("Wed, 04 Jan 2017 09:55:45 -0800"))))
# 2017-01-04T17:55:45Z
Run Code Online (Sandbox Code Playgroud)

确保您不使用 mktime(它以您计算机的本地时间解释 time_struct,而不是 UTC);使用timegmmktime_tz代替(但要注意mktime_tz下一段中的)。

如果您确定您拥有 python 版本 2.7.4、3.2.4、3.3 或更新版本,那么您可以使用email.utils.mktime_tz(tt)代替calendar.timegm(tt) - tt[9]. 在此之前,mktime_tz在本地时区的秋季夏令时转换期间调用时给出了错误的时间(错误 14653)。

感谢 @jf-sebastian关于 mktime 和 mktime_tz 的警告

电子邮件日期/时间字符串(RFC 5322RFC 2822RFC 1123)以“知晓”datetime在 python 3.3 上:

在 python 3.3 及更高版本上, use email.utils.parsedate_to_datetime,它返回一个datetime带有原始区域偏移量的感知:

import email.utils
email.utils.parsedate_to_datetime(s)

print(email.utils.parsedate_to_datetime("Wed, 04 Jan 2017 09:55:45 -0800").isoformat())
# 2017-01-04T09:55:45-08:00
Run Code Online (Sandbox Code Playgroud)

警告:ValueError如果时间落在闰秒上,这将抛出,例如email.utils.parsedate_to_datetime("Sat, 31 Dec 2016 15:59:60 -0800")

电子邮件日期/时间字符串(RFC 5322RFC 2822RFC 1123datetime在 UTC 区域中“知晓” :

这只是转换为时间戳,然后转换为 UTC datetime

import email.utils
import calendar
import datetime
def email_time_to_utc_datetime(s):
    tt = email.utils.parsedate_tz(s)
    if tt is None: return None
    timestamp = calendar.timegm(tt) - tt[9]
    return datetime.datetime.utcfromtimestamp(timestamp)

print(email_time_to_utc_datetime("Wed, 04 Jan 2017 09:55:45 -0800").isoformat())
# 2017-01-04T17:55:45
Run Code Online (Sandbox Code Playgroud)

将日期/时间字符串(RFC 5322RFC 2822RFC 1123)发送到datetime具有原始偏移量的python “aware” :

在 python 3.2 之前,python 没有提供 tzinfo 实现,所以这里有一个使用dateutil.tz.tzoffset( pip install dateutil)的例子:

import email.utils
import datetime
import dateutil.tz
def email_time_to_datetime(s):
    tt = email.utils.parsedate_tz(s)
    if tt is None: return None
    tz = dateutil.tz.tzoffset("UTC%+02d%02d"%(tt[9]//60//60, tt[9]//60%60), tt[9])
    return datetime.datetime(*tt[:5]+(min(tt[5], 59),), tzinfo=tz)

print(email_time_to_datetime("Wed, 04 Jan 2017 09:55:45 -0800").isoformat())
# 2017-01-04T09:55:45-08:00
Run Code Online (Sandbox Code Playgroud)

如果您使用的是 python 3.2,则可以使用内置tzinfo实现datetime.timezonetz = datetime.timezone(datetime.timedelta(seconds=tt[9]))而不是第三方dateutil.tz.tzoffset.

再次感谢@jf-sebastian提供关于限制闰秒的说明