我需要将RFC 3339字符串(如“2008-09-03T20:56:55.450686Z”)解析为Python的datetime类型。
我在Python标准库中找到了strptime,但它不是很方便。
最好的方法是什么?
我需要将RFC 3339字符串(如“2008-09-03T20:56:55.450686Z”)解析为Python的datetime类型。
我在Python标准库中找到了strptime,但它不是很方便。
最好的方法是什么?
当前回答
在所有受支持的Python版本中,将类似ISO 8601的日期字符串转换为UNIX时间戳或datetime.datetime对象而无需安装第三方模块的一种简单方法是使用SQLite的日期解析器。
#!/usr/bin/env python
from __future__ import with_statement, division, print_function
import sqlite3
import datetime
testtimes = [
"2016-08-25T16:01:26.123456Z",
"2016-08-25T16:01:29",
]
db = sqlite3.connect(":memory:")
c = db.cursor()
for timestring in testtimes:
c.execute("SELECT strftime('%s', ?)", (timestring,))
converted = c.fetchone()[0]
print("%s is %s after epoch" % (timestring, converted))
dt = datetime.datetime.fromtimestamp(int(converted))
print("datetime is %s" % dt)
输出:
2016-08-25T16:01:26.123456Z is 1472140886 after epoch
datetime is 2016-08-25 12:01:26
2016-08-25T16:01:29 is 1472140889 after epoch
datetime is 2016-08-25 12:01:29
其他回答
我已经为ISO 8601标准编写了一个解析器,并将其放在GitHub上:https://github.com/boxed/iso8601.此实现支持规范中的所有内容,但持续时间、间隔、周期性间隔和Python datetime模块支持的日期范围之外的日期除外。
包括测试!:P
尝试iso8601模块;它正是这样做的。
python.org wiki上的WorkingWithTime页面上还提到了其他几个选项。
如今,Arrow还可以作为第三方解决方案:
>>> import arrow
>>> date = arrow.get("2008-09-03T20:56:35.450686Z")
>>> date.datetime
datetime.datetime(2008, 9, 3, 20, 56, 35, 450686, tzinfo=tzutc())
Django的parse_datetime()函数支持UTC偏移的日期:
parse_datetime('2016-08-09T15:12:03.65478Z') =
datetime.datetime(2016, 8, 9, 15, 12, 3, 654780, tzinfo=<UTC>)
因此,它可以用于解析整个项目中字段中的ISO 8601日期:
from django.utils import formats
from django.forms.fields import DateTimeField
from django.utils.dateparse import parse_datetime
class DateTimeFieldFixed(DateTimeField):
def strptime(self, value, format):
if format == 'iso-8601':
return parse_datetime(value)
return super().strptime(value, format)
DateTimeField.strptime = DateTimeFieldFixed.strptime
formats.ISO_INPUT_FORMATS['DATETIME_INPUT_FORMATS'].insert(0, 'iso-8601')
从Python 3.7开始,您基本上可以使用datetime.datetime.strptime解析RFC 3339日期时间,如下所示:
from datetime import datetime
def parse_rfc3339(datetime_str: str) -> datetime:
try:
return datetime.strptime(datetime_str, "%Y-%m-%dT%H:%M:%S.%f%z")
except ValueError:
# Perhaps the datetime has a whole number of seconds with no decimal
# point. In that case, this will work:
return datetime.strptime(datetime_str, "%Y-%m-%dT%H:%M:%S%z")
这有点尴尬,因为我们需要尝试两种不同的格式字符串,以便同时支持小数秒的日期时间(如2022-01-01T12:12:12.123Z)和没有小数秒的(如2021-01-01T12:12Z),这两种格式在RFC 3339下都是有效的。但只要我们做一点逻辑,这就行得通。
此方法需要注意的一些注意事项:
它在技术上并不完全支持RFC 3339,因为RFC 3339允许您使用空格而不是t来分隔日期和时间,尽管RFC 3339声称是ISO 8601的概要文件,但ISO 8601不允许这样做。如果您想支持RFC 3339的这种愚蠢的怪癖,可以在函数的开头添加datetime_str=datetime_str.replace(“”,“T”)。我上面的实现比严格的RFC 3339解析器应该更宽松,因为它将允许时区偏移,如+0500而不带冒号,而RFC 3339不支持。如果您不仅想解析known-to-be-RFC-339日期时间,而且还想严格验证您获得的日期时间是否为RFC 3339,请使用另一种方法或添加您自己的逻辑来验证时区偏移格式。这个函数肯定不支持所有的ISO 8601,它包括比RFC 3339更广泛的格式。(例如,2009-W01-1是有效的ISO 8601日期。)它在Python 3.6或更早版本中不起作用,因为在那些旧版本中,%z说明符只匹配+0500或-0430或+0000等时区偏移,而不是+05:00或-04:30或z等RFC 3339时区偏移。