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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/885015/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-03 21:03:42  来源:igfitidea点击:

How to parse a RFC 2822 date/time into a Python datetime?

pythonparsingdatetimetimepython-2.5

提问by millenomi

I have a date of the form specified by RFC 2822 -- say Fri, 15 May 2009 17:58:28 +0000, as a string. Is there a quick and/or standard way to get it as a datetimeobject in Python 2.5? I tried to produce a strptime format string, but the +0000 timezone specifier confuses the parser.

我有一个由 RFC 2822 指定的形式的日期——比如说Fri, 15 May 2009 17:58:28 +0000,作为一个字符串。是否有一种快速和/或标准的方法可以将其作为datetimePython 2.5 中的对象?我试图生成一个 strptime 格式字符串,但 +0000 时区说明符混淆了解析器。

回答by

The problem is that parsedate will ignore the offset.

问题是 parsedate 会忽略偏移量。

Do this instead:

改为这样做:

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

回答by gonz

I'd like to elaborate on previous answers. email.utils.parsedateand email.utils.parsedate_tzboth return tuples, since the OP needs a datetime.datetimeobject, I'm adding these examples for completeness:

我想详细说明以前的答案。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))

Or:

或者:

d2 = datetime.datetime(*t[:6])

Note that d1and d2are both naive datetime objects, there's no timezone information stored. If you need aware datetime objects, check the tzinfodatetime()arg.

请注意,d1d2都是朴素的日期时间对象,没有存储时区信息。如果您需要了解日期时间对象,请检查tzinfodatetime()arg。

Alternatively you could use the dateutilmodule

或者,您可以使用dateutil模块

回答by nosklo

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

Documentation.

文档

回答by ebo

There is a parsedate function in email.util. It parses all valid RFC 2822 dates and some special cases.

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

回答by erewok

It looks like Python 3.3 going forward has a new method parsedate_to_datetimein email.utils that takes care of the intermediate steps:

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

email.utils.parsedate_to_datetime(date)

The inverse of format_datetime(). Performs the same function as parsedate(), but on success returns a datetime. If the input date has a timezone of -0000, the datetime will be a naive datetime, and if the date is conforming to the RFCs it will represent a time in UTC but with no indication of the actual source timezone of the message the date comes from. If the input date has any other valid timezone offset, the datetime will be an aware datetime with the corresponding a timezone tzinfo.

New in version 3.3.

email.utils.parsedate_to_datetime(date)

format_datetime() 的倒数。执行与 parsedate() 相同的功能,但成功时返回日期时间。如果输入日期的时区为 -0000,则日期时间将是一个简单的日期时间,如果日期符合 RFC,它将表示 UTC 时间,但不指示日期到来的消息的实际源时区从。如果输入日期有任何其他有效的时区偏移量,则日期时间将是具有相应时区 tzinfo 的可感知日期时间。

3.3 版中的新功能。

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

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

回答by yonran

email.utils.parsedate_tz(date)is the function to use. Following are some variations.

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

Email date/time string (RFC 5322, RFC 2822, RFC 1123) to unix timestamp in float seconds:

电子邮件日期/时间字符串(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

Make sure you do not usemktime(which interprets the time_struct in your computer's local time, not UTC); use timegmor mktime_tzinstead (but beware caveat for mktime_tzin the next paragraph).

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

If you are sure that you have python version 2.7.4, 3.2.4, 3.3, or newer, then you can use email.utils.mktime_tz(tt)instead of calendar.timegm(tt) - tt[9]. Before that, mktime_tzgave incorrect times when invoked during the local time zone's fall daylight savings transition (bug 14653).

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

Thanks to @j-f-sebastian for caveats about mktime and mktime_tz.

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

Email date/time string (RFC 5322, RFC 2822, RFC 1123) to “aware” datetimeon python 3.3:

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

On python 3.3 and above, use email.utils.parsedate_to_datetime, which returns an aware datetimewith the original zone offset:

在 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

Caveat: this will throw ValueErrorif the time falls on a leap second e.g. email.utils.parsedate_to_datetime("Sat, 31 Dec 2016 15:59:60 -0800").

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

Email date/time string (RFC 5322, RFC 2822, RFC 1123) to “aware” datetimein UTC zone:

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

This just converts to timestamp and then to UTC datetime:

这只是转换为时间戳,然后转换为 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

Email date/time string (RFC 5322, RFC 2822, RFC 1123) to python “aware” datetimewith original offset:

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

Prior to python 3.2, python did not come with tzinfo implementations, so here an example using dateutil.tz.tzoffset(pip install dateutil):

在 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

If you are using python 3.2, you can use the builtin tzinfoimplementation datetime.timezone: tz = datetime.timezone(datetime.timedelta(seconds=tt[9]))instead of the third-party dateutil.tz.tzoffset.

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

Thanks to @j-f-sebastian again for note on clamping the leap second.

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