【问题标题】:How to parse a RFC 2822 date/time into a Python datetime?如何将 RFC 2822 日期/时间解析为 Python 日期时间?
【发布时间】:2010-10-27 11:13:04
【问题描述】:

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

【问题讨论】:

    标签: python parsing datetime time python-2.5


    【解决方案1】:

    问题是 parsedate 会忽略偏移量。

    改为这样做:

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

    【讨论】:

    • 遇到问题发现,从python 3.3开始,email.utils有一个新的函数parsedate_to_datetime直接输出datetime实例。
    【解决方案2】:

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

    或者:

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

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

    您也可以使用dateutil 模块

    【讨论】:

      【解决方案3】:
      from email.utils import parsedate
      print parsedate('Fri, 15 May 2009 17:58:28 +0000')
      

      Documentation.

      【讨论】:

        【解决方案4】:

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

        【讨论】:

          【解决方案5】:

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

          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

          【讨论】:

            【解决方案6】:

            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
            

            确保您不要使用 mktime(它以您计算机的本地时间而非 UTC 时间解释 time_struct);请改用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 在本地时区的秋季夏令时转换期间调用时给出了错误的时间 (bug 14653)。

            感谢@j-f-sebastian 提供caveats about mktime and mktime_tz

            在 python 3.3 上将日期/时间字符串(RFC 5322RFC 2822RFC 1123)发送到“aware”datetime

            在 python 3.3 及更高版本上,使用 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
            

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

            通过电子邮件将日期/时间字符串(RFC 5322RFC 2822RFC 1123)发送至“知道”datetime(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
            

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

            在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
            

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

            再次感谢@j-f-sebastian for note on clamping the leap second

            【讨论】:

              猜你喜欢
              • 2011-03-28
              • 1970-01-01
              • 2011-01-28
              • 2013-03-27
              • 2012-06-15
              • 2011-08-27
              • 1970-01-01
              • 1970-01-01
              • 2014-01-29
              相关资源
              最近更新 更多