【问题标题】:Convert an RFC 3339 time to a standard Python timestamp将 RFC 3339 时间转换为标准 Python 时间戳
【发布时间】:2009-12-21 19:00:30
【问题描述】:

有没有一种简单的方法可以将 RFC 3339 时间转换为常规 Python 时间戳?

我有一个正在读取 ATOM 提要的脚本,我希望能够将 ATOM 提要中项目的时间戳与文件的修改时间进行比较。

我从ATOM spec 注意到,ATOM 日期包括时区偏移 (Z<a number>),但就我而言,Z 之后没有任何内容,所以我想我们可以假设为 GMT。

我想我可以用某种正则表达式解析时间,但我希望 Python 有一种我无法找到的内置方法。

【问题讨论】:

标签: python datetime rfc3339


【解决方案1】:

您没有提供示例,但如果您没有 Z 偏移量或时区,并且假设您不想要持续时间而只想要基本时间,那么也许这会适合您:

import datetime as dt
>>> dt.datetime.strptime('1985-04-12T23:20:50.52', '%Y-%m-%dT%H:%M:%S.%f')
datetime.datetime(1985, 4, 12, 23, 20, 50, 520000)

strptime() 函数被添加到 Python 2.5 的 datetime 模块中,所以有些人还不知道它的存在。

编辑:虽然 time.strptime() 函数已经存在了一段时间,但它的工作原理与为您提供一个 struct_time 值大致相同:

>>> ts = time.strptime('1985-04-12T23:20:50.52', '%Y-%m-%dT%H:%M:%S.%f')
>>> ts
time.struct_time(tm_year=1985, tm_mon=4, tm_mday=12, tm_hour=23, tm_min=20, tm_sec=50, tm_wday=4, tm_yday=102, tm_isdst=-1)
>>> time.mktime(ts)
482210450.0

【讨论】:

  • 这行不通 - 不支持时区的方法与 RFC 3339 不兼容。
  • Yarin,很明显,但是您的投诉应该是原始问题对“RFC 3339”的使用,因为我的回答确实解决了他的实际问题,他指出他没有时区。 ..
  • Peter-我读他的问题的方式是,他试图将 ATOM 提要 RFC 3999 日期与时区与假定 GMT 的另一个日期进行比较,但也许我不明白
  • @Yarin: "Z 后面什么都没有" -- 这意味着输入是 UTC 并且可以使用strptime()。尽管不应使用预计本地时区时间的mktime()。可以使用calendar.timegm() 代替(与os.path.getmtime() 的结果进行比较:“我希望能够将 ATOM 提要中项目的时间戳与文件的修改时间进行比较。”)
【解决方案2】:

我在 RFC3339 日期时间格式上苦苦挣扎,但我找到了一个合适的解决方案来双向转换 date_string datetime_object。

您需要两个不同的外部模块,因为其中一个只能在一个方向上进行转换(不幸的是):

首次安装:

sudo pip install rfc3339
sudo pip install iso8601

然后包括:

import datetime     # for general datetime object handling
import rfc3339      # for date object -> date string
import iso8601      # for date string -> date object

为了不需要记住哪个模块是哪个方向,我写了两个简单的辅助函数:

def get_date_object(date_string):
  return iso8601.parse_date(date_string)

def get_date_string(date_object):
  return rfc3339.rfc3339(date_object)

在您的代码中,您可以像这样轻松使用:

input_string = '1989-01-01T00:18:07-05:00'
test_date = get_date_object(input_string)
# >>> datetime.datetime(1989, 1, 1, 0, 18, 7, tzinfo=<FixedOffset '-05:00' datetime.timedelta(-1, 68400)>)

test_string = get_date_string(test_date)
# >>> '1989-01-01T00:18:07-05:00'

test_string is input_string # >>> True

赫里卡!现在您可以轻松(哈哈)以可用的格式使用您的日期字符串和日期字符串。

【讨论】:

    【解决方案3】:

    没有内置,afaik。

    feed.date.rfc3339 这是一个 Python 库模块,具有将 RFC 3339 格式的时间戳字符串转换为 Python 时间浮点值的功能,反之亦然。 RFC 3339 是 Atom 提要联合格式使用的时间戳格式。

    它是 BSD 许可的。

    http://home.blarg.net/~steveha/pyfeed.html

    (已编辑,很明显不是我写的。:-)

    【讨论】:

    • PyFeed 完全符合我的需要,由 feed.date.rfc3339 中的 tf_from_timestamp() 函数提供
    • 另外,我编写了 PyFeed(和 Xe)库,并在 StackOverflow 上闲逛,所以如果您对此有任何疑问,我很乐意为您解答。
    • 请注意,PyFeed 可用于解析 Atom 提要。它使用 xml.dom.minidom 来进行实际的解析,然后将 XML 树结构解压缩成方便的类。嗯,我应该把 Xe 和 PyFeed 放在 PyPI 上。
    • @steveha 太好了,感谢您的提议。到目前为止,这些库似乎很容易使用,但如果我遇到任何奇怪的事情,我会记得你在这里。
    • @Alex Brasetvik,很明显你并没有声称自己写过它。如果您要求信用,您将不会包含指向我网页的直接链接!附言我很高兴看到你推荐我的图书馆;谢谢。
    【解决方案4】:

    如果你使用 Django,你可以使用 Django 的函数parse_datetime:

    >>> from django.utils.dateparse import parse_datetime
    >>> parse_datetime("2016-07-19T07:30:36+05:00")
    datetime.datetime(2016, 7, 19, 7, 30, 36, tzinfo=<django.utils.timezone.FixedOffset object at 0x101c0c1d0>)
    

    【讨论】:

      【解决方案5】:

      http://pypi.python.org/pypi/iso8601/ 似乎能够解析 RFC 3339 是其子集的 iso 8601,也许这可能有用,但同样不是内置的。

      【讨论】:

      • 时间浮动和 struct_time 不知道时区。由于 RFC 3339 需要与 UTC 兼容的时区,这在 Python 中意味着非天真的 datetime 对象,这是迄今为止唯一合理的选择。
      【解决方案6】:

      added in Python 3.7 的新 datetime.fromisoformat(date_string) 方法将解析大多数 RFC 3339 时间戳,包括具有时区偏移的时间戳。这不是一个完整的实现,所以一定要测试你的用例。

      >>> from datetime import datetime
      >>> datetime.fromisoformat('2011-11-04')
      datetime.datetime(2011, 11, 4, 0, 0)
      >>> datetime.fromisoformat('2011-11-04T00:05:23')
      datetime.datetime(2011, 11, 4, 0, 5, 23)
      >>> datetime.fromisoformat('2011-11-04 00:05:23.283')
      datetime.datetime(2011, 11, 4, 0, 5, 23, 283000)
      >>> datetime.fromisoformat('2011-11-04 00:05:23.283+00:00')
      datetime.datetime(2011, 11, 4, 0, 5, 23, 283000, tzinfo=datetime.timezone.utc)
      >>> datetime.fromisoformat('2011-11-04T00:05:23+04:00')   
      datetime.datetime(2011, 11, 4, 0, 5, 23,
          tzinfo=datetime.timezone(datetime.timedelta(seconds=14400)))
      

      【讨论】:

        【解决方案7】:

        http://bugs.python.org/issue15873(与http://bugs.python.org/issue5207 重复)

        似乎还没有内置的。

        【讨论】:

          【解决方案8】:

          feedparser.py 提供强大/可扩展的方式来解析现实世界 atom/rss 提要中可能遇到的各种日期格式:

          >>> from feedparser import _parse_date as parse_date
          >>> parse_date('1985-04-12T23:20:50.52Z')
          time.struct_time(tm_year=1985, tm_mon=4, tm_mday=12, tm_hour=23, tm_min=20,
                           tm_sec=50, tm_wday=4, tm_yday=102, tm_isdst=1)
          

          【讨论】:

          • 这似乎比 PyFeed 提供的“时间浮动”要好得多。
          • cool-NR,如果你有时间浮点值,你可以调用time.gmtime(),得到struct_time的值。使用时间浮点值计算相对时间要容易得多;两天后只是tf + 2 * seconds_per_day(其中seconds_per_day 是24 * 60 * 60)。 Python 的 struct_time 非常适合检查(一周中的哪一天?),但对于计算非常不方便。
          • 它不保持毫秒?
          • @LennartRolland:是的。 time.struct_time 不存储小数秒。
          【解决方案9】:

          试试这个,对我来说很好用

          datetime_obj =  datetime.strptime("2014-01-01T00:00:00Z", '%Y-%m-%dT%H:%M:%SZ')
          

          datetime_obj = datetime.strptime("Mon, 01 Jun 2015 16:41:40 GMT", '%a, %d %b %Y %H:%M:%S GMT')
          

          【讨论】:

          • 它不支持数字 UTC 偏移量:+HHMM。第二个例子不是rfc 3339;它是rfc 5322
          【解决方案10】:

          对我来说最简单的解决方案是 dateutil python 标准库。

          from dateutil.parser import parse
          
          dt = "2020-11-23T11:08:23.022277705Z"
          print(parse(dt))
          

          输出:

          2020-11-23 11:08:23.022277+00:00
          

          如果您不需要时区元素,只需将时区信息设置为

          print(parse(t).replace(tzinfo=None))
          

          输出是一个漂亮而干净的日期时间对象:

          2020-11-23 11:08:23.022277
          

          【讨论】:

            【解决方案11】:

            在另一个问题中遇到了很棒的 dateutil.parser 模块,并在我的 RFC3339 问题上尝试了它,它似乎比这个问题中的任何其他回答都更理智地处理我扔给它的所有东西。

            【讨论】:

            • 唯一的问题是它还会解析 non-date 值,例如“now”
            【解决方案12】:

            使用 Python 3,您可以使用 RegEx 将 RFC 3339 时间戳分解为其组件。 然后,直接创建 datetime 对象,不需要额外的模块:

            import re
            import datetime
            
            def parse_rfc3339(dt):
                broken = re.search(r'([0-9]{4})-([0-9]{2})-([0-9]{2})T([0-9]{2}):([0-9]{2}):([0-9]{2})(\.([0-9]+))?(Z|([+-][0-9]{2}):([0-9]{2}))', dt)
                return(datetime.datetime(
                    year = int(broken.group(1)),
                    month = int(broken.group(2)),
                    day = int(broken.group(3)),
                    hour = int(broken.group(4)),
                    minute = int(broken.group(5)),
                    second = int(broken.group(6)),
                    microsecond = int(broken.group(8) or "0"),
                    tzinfo = datetime.timezone(datetime.timedelta(
                        hours = int(broken.group(10) or "0"),
                        minutes = int(broken.group(11) or "0")))))
            

            此示例将缺少的时区或微秒标记为“0”,但可能需要额外的错误检查。 干杯,亚历克斯

            【讨论】:

              【解决方案13】:

              您可以使用 Google API Core 包。他们有一个非常简单的 Datetime 到 RFC 3339 的转换函数。你可以在their docs找到更多信息。

              它的用法很简单:

              from google.api_core.datetime_helpers import to_rfc3339
              
              rfc3339_str = to_rfc3339(datetime.now())
              

              他们甚至有一个函数可以与 from_rfc3339from_rfc3339_nanos 反向工作。

              【讨论】:

                【解决方案14】:

                【讨论】:

                  【解决方案15】:

                  我一直在深入研究 datetimes 和 RFC3339,最近遇到了arrow library,刚刚使用并解决了我的问题:

                  import arrow
                  
                  date_string = "2015-11-24 00:00:00+00:00"
                  my_datetime = arrow.get(date_string).datetime
                  

                  【讨论】:

                    猜你喜欢
                    • 2016-04-14
                    • 2013-02-09
                    • 1970-01-01
                    • 2012-01-23
                    • 2010-09-22
                    • 1970-01-01
                    • 2016-01-21
                    • 1970-01-01
                    • 1970-01-01
                    相关资源
                    最近更新 更多