我需要将RFC 3339字符串(如“2008-09-03T20:56:55.450686Z”)解析为Python的datetime类型。

我在Python标准库中找到了strptime,但它不是很方便。

最好的方法是什么?


当前回答

Python>=3.11

fromsoformat现在直接解析Z:

from datetime import datetime

s = "2008-09-03T20:56:35.450686Z"

datetime.fromisoformat(s)
datetime.datetime(2008, 9, 3, 20, 56, 35, 450686, tzinfo=datetime.timezone.utc)

Python 3.7到3.10

一个注释中的简单选项:将“Z”替换为“+00:00”-并使用fromsoformat:

from datetime import datetime

s = "2008-09-03T20:56:35.450686Z"

datetime.fromisoformat(s.replace('Z', '+00:00'))
# datetime.datetime(2008, 9, 3, 20, 56, 35, 450686, tzinfo=datetime.timezone.utc)

为什么更喜欢来自同一格式?

虽然strptime的%z可以将“z”字符解析为UTC,但fromsoformat的速度要快~x40(另请参阅:更快的strptime):

%timeit datetime.fromisoformat(s.replace('Z', '+00:00'))
388 ns ± 48.3 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)

%timeit dateutil.parser.isoparse(s)
11 µs ± 1.05 µs per loop (mean ± std. dev. of 7 runs, 100000 loops each)

%timeit datetime.strptime(s, '%Y-%m-%dT%H:%M:%S.%f%z')
15.8 µs ± 1.32 µs per loop (mean ± std. dev. of 7 runs, 100000 loops each)

%timeit dateutil.parser.parse(s)
87.8 µs ± 8.54 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)

(Windows 10上的Python 3.9.12 x64)

其他回答

def parseISO8601DateTime(datetimeStr):
    import time
    from datetime import datetime, timedelta

    def log_date_string(when):
        gmt = time.gmtime(when)
        if time.daylight and gmt[8]:
            tz = time.altzone
        else:
            tz = time.timezone
        if tz > 0:
            neg = 1
        else:
            neg = 0
            tz = -tz
        h, rem = divmod(tz, 3600)
        m, rem = divmod(rem, 60)
        if neg:
            offset = '-%02d%02d' % (h, m)
        else:
            offset = '+%02d%02d' % (h, m)

        return time.strftime('%d/%b/%Y:%H:%M:%S ', gmt) + offset

    dt = datetime.strptime(datetimeStr, '%Y-%m-%dT%H:%M:%S.%fZ')
    timestamp = dt.timestamp()
    return dt + timedelta(hours=dt.hour-time.gmtime(timestamp).tm_hour)

注意,如果字符串不以Z结尾,我们可以使用%Z进行解析。

python dateutil中的等参函数

python dateutil包具有dateutil.parser.isose,不仅可以解析RFC 3339日期时间字符串(如问题中的字符串),还可以解析其他不符合RFC 3339的ISO 8601日期和时间字符串(例如没有UTC偏移量的字符串,或仅表示日期的字符串)。

>>> import dateutil.parser
>>> dateutil.parser.isoparse('2008-09-03T20:56:35.450686Z') # RFC 3339 format
datetime.datetime(2008, 9, 3, 20, 56, 35, 450686, tzinfo=tzutc())
>>> dateutil.parser.isoparse('2008-09-03T20:56:35.450686') # ISO 8601 extended format
datetime.datetime(2008, 9, 3, 20, 56, 35, 450686)
>>> dateutil.parser.isoparse('20080903T205635.450686') # ISO 8601 basic format
datetime.datetime(2008, 9, 3, 20, 56, 35, 450686)
>>> dateutil.parser.isoparse('20080903') # ISO 8601 basic format, date only
datetime.datetime(2008, 9, 3, 0, 0)

python dateutil包还具有dateutil.parser.parse。与isose相比,它可能不那么严格,但这两个函数都非常宽容,都会尝试解释传入的字符串。如果要消除任何误读的可能性,需要使用比这两个函式更严格的函数。

与Python 3.7+内置datetime.datetime.fromisoformat的比较

dateutil.parser.isorse是一个完整的ISO-8601格式解析器,但在Python≤3.10中,fromsoformat故意不是。在Python 3.11中,fromsoformat支持有效ISO 8601中的几乎所有字符串。请参阅isoformat的文档以了解此警告。(参见此答案)。

自Python 3.7以来,datetime标准库有一个用于反转datetime.isoformat()的函数。

classmethod datetime.fromisoformat(date_string):以任何有效的ISO 8601格式返回与date_string对应的日期时间,但以下情况除外:时区偏移可能有小数秒。T分隔符可以由任何单个unicode字符替换。当前不支持顺序日期。不支持分数小时和分钟。示例:>>>从datetime导入datetime>>>日期时间。来自同一格式(“2011-11-04”)datetime.datetime(2011,11,4,0,0)>>>datetime.fromisoformat('20111104')datetime.datetime(2011,11,4,0,0)>>>日期时间。来自同一格式('2011-11-04T00:05:23')datetime.datetime(2011,11,4,0,5,23)>>>日期时间。来自同一格式('2011-11-04T00:05:23Z')datetime.datetime(2011,11,4,0,5,23,tzinfo=datetime.timezone.utc)>>>日期时间。来自同一格式('20111104T000523')datetime.datetime(2011,11,4,0,5,23)>>>datetime.fromisoformat('2011-W01-2T0:05:32.283')datetime.datetime(2011,1,4,0,5,23,283000)>>>日期时间。来自同一格式('2011-11-04 00:05:23.283')datetime.datetime(2011,11,4,0,5,23,283000)>>>日期时间。来自同一格式('2011-11-04 00:05:23.283+00:00')datetime.datetime(2011,11,4,0,5,23,283000,tzinfo=datetime.timezone.utc)>>>日期时间。来自同一格式('2011-11-04T00:05:23+04:00')datetime.datetime(2011,11,4,0,5,23,tzinfo=datetime.timezone(datetime.time增量(秒=1440)))3.7版新增。3.11版本中更改:以前,此方法只支持date.isoformat()或datetime.isoformat()发出的格式。

如果您还没有升级到Python 3.11,请务必阅读文档中的警告!

只需使用python dateutil模块:

>>> import dateutil.parser as dp
>>> t = '1984-06-02T19:05:00.000Z'
>>> parsed_t = dp.parse(t)
>>> print(parsed_t)
datetime.datetime(1984, 6, 2, 19, 5, tzinfo=tzutc())

文档

要获得与2.X标准库兼容的功能,请尝试:

calendar.timegm(time.strptime(date.split(".")[0]+"UTC", "%Y-%m-%dT%H:%M:%S%Z"))

calendar.timegm是time.mktime缺少的gm版本。