isoparse
函数来自python-dateutilpython-dateutil包拥有dateutil.parser.isoparse
函数,它可以解析不仅仅是问题中提到的RFC 3339日期时间字符串,还能够解析其它ISO 8601格式的日期和时间字符串,即使这些字符串不符合RFC 3339标准(例如没有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
。与isoparse
相比,它可能不那么严格,但两者都非常宽容,并将尝试解释您传递的字符串。如果您想消除任何误读的可能性,则需要使用比这两个函数更严格的东西。
datetime.datetime.fromisoformat
进行比较dateutil.parser.isoparse
是一个完整的ISO-8601格式解析器,但在Python ≤ 3.10中,fromisoformat
故意不是。在Python 3.11中,fromisoformat
支持几乎所有有效的ISO 8601字符串。请参见fromisoformat
的文档以了解此警告性警告。(请参见this answer)。
python-dateutil
而不是dateutil
安装的,所以:pip install python-dateutil
。 - cod3monk3ydateutil.parser
故意设计得比较差:它试图猜测日期格式并在歧义的情况下做出不可避免的假设(只能手动定制),因此仅在需要解析未知格式的输入并且可以容忍偶尔的错误时才使用。 - ivan_pozdeevdatetime.fromisoformat(date_string)
:
返回一个与任何有效的 ISO 8601 格式中的date_string对应的datetime
,但有以下几个例外:
T
分隔符可以被任何单个 Unicode 字符替代。>>> from datetime import datetime
>>> datetime.fromisoformat('2011-11-04')
datetime.datetime(2011, 11, 4, 0, 0)
>>> datetime.fromisoformat('20111104')
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-04T00:05:23Z')
datetime.datetime(2011, 11, 4, 0, 5, 23, tzinfo=datetime.timezone.utc)
>>> datetime.fromisoformat('20111104T000523')
datetime.datetime(2011, 11, 4, 0, 5, 23)
>>> datetime.fromisoformat('2011-W01-2T00:05:23.283')
datetime.datetime(2011, 1, 4, 0, 5, 23, 283000)
>>> 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)))
新增于版本3.7。
从版本3.11开始更改:先前,此方法仅支持可以由date.isoformat()或datetime.isoformat()生成的格式。datetime
可能包含tzinfo
,从而输出时区,但是datetime.fromisoformat()
不解析tzinfo?看起来像是一个bug.. - Hendy Irawanisoformat
生成的字符串。它不接受问题中的例子 "2008-09-03T20:56:35.450686Z"
,因为它有一个尾随的 Z
,但它可以接受 "2008-09-03T20:56:35.450686"
。 - FlimmZ
,可以使用date_string.replace("Z", "+00:00")
修改输入脚本。 - joxdatetime.fromisoformat
似乎需要另一种格式。我刚测试了这两个版本,虽然使用+00:00
可以正常工作,但是当我使用+0000
时,会出现“ValueError:Invalid isoformat string”的错误。 - jox请注意,在Python 2.6+和Py3K中,%f字符可捕获微秒。
>>> datetime.datetime.strptime("2008-09-03T20:56:35.450686Z", "%Y-%m-%dT%H:%M:%S.%fZ")
请查看此处的问题
datetime.datetime.strptime(timestamp, '%Y-%m-%dT%H:%M:%S.%f')
就解决了问题。 - ashim888从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
)和没有小数秒(例如2022-01-01T12:12:12Z
)的日期时间,这两者在RFC 3339下都是有效的。但只要我们进行单个琐碎的逻辑处理,就可以解决这个问题。T
来分隔日期和时间,即使RFC 3339声称是ISO 8601的一个配置文件,而ISO 8601却不允许这样做。如果您想支持RFC 3339的这种傻瓜行为,请在函数开头添加datetime_str = datetime_str.replace(' ', 'T')
。+0500
,而RFC 3339则不支持。如果您不仅想解析已知为RFC 3339的日期时间,而且还想严格验证您收到的日期时间是否符合RFC 3339,请使用其他方法或添加自己的逻辑来验证时区偏移量格式。2009-W01-1
是有效的ISO 8601日期。)%z
说明符仅匹配时区偏移量,例如+0500
,-0430
或+0000
,而不是RFC 3339时区偏移量,如+05:00
,-04:30
或Z
。尝试使用iso8601模块,它恰好能够实现这个功能。
在python.org维基页的WorkingWithTime页面上提到了其他几个选项。
iso8601.parse_date("2008-09-03T20:56:35.450686Z")
- Pakmanfromisoformat
现在可以直接解析 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)
从评论中的一个简单选项:将'Z'
替换为'+00:00'
- 并使用fromisoformat
函数:
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)
fromisoformat
?尽管strptime
的%z
可以解析'Z'
字符为UTC时间,但fromisoformat
的速度更快,大约快40倍(甚至对于Python 3.11来说,速度可能快60倍):
from datetime import datetime
from dateutil import parser
s = "2008-09-03T20:56:35.450686Z"
# Python 3.11+
%timeit datetime.fromisoformat(s)
85.1 ns ± 0.473 ns per loop (mean ± std. dev. of 7 runs, 10,000,000 loops each)
# Python 3.7 to 3.10
%timeit datetime.fromisoformat(s.replace('Z', '+00:00'))
134 ns ± 0.522 ns per loop (mean ± std. dev. of 7 runs, 10,000,000 loops each)
%timeit parser.isoparse(s)
4.09 µs ± 5.2 ns per loop (mean ± std. dev. of 7 runs, 100,000 loops each)
%timeit datetime.strptime(s, '%Y-%m-%dT%H:%M:%S.%f%z')
5 µs ± 9.26 ns per loop (mean ± std. dev. of 7 runs, 100,000 loops each)
%timeit parser.parse(s)
28.5 µs ± 99.2 ns per loop (mean ± std. dev. of 7 runs, 10,000 loops each)
fromisoformat
可以解析+00:00
但不能解析Z
,并将其转换为带有UTC时区信息的aware datetime。如果您的输入以Z+00:00
结尾,则可以在将其提供给fromisoformat
之前删除Z
。其他UTC偏移量(例如+05:30
)将被解析为静态UTC偏移量(而不是实际的时区)。 - FObersteinerdatetime.date
的fromisoformat
更加明确:“返回与以任何有效的ISO 8601格式给出的日期字符串相对应的日期... ”... 它还提供了一些令人惊讶的字符串示例,它们不仅仅是简单的YYYY-MM-DD格式。 - mike rodentdatetime.date
的fromisoformat
更加明确:“返回与以任何有效的ISO 8601格式给出的date_string相对应的日期...”...它给出了一些令人惊讶的字符串示例,这些字符串不仅仅是简单的YYYY-MM-DD。 - undefined自Python 3.7开始,strptime支持UTC偏移量中的冒号分隔符(源)。因此,您可以使用以下内容:
import datetime
def parse_date_string(date_string: str) -> datetime.datetime
try:
return datetime.datetime.strptime(date_string, '%Y-%m-%dT%H:%M:%S.%f%z')
except ValueError:
return datetime.datetime.strptime(date_string, '%Y-%m-%dT%H:%M:%S%z')
编辑:
正如Martijn所指出的那样,如果您使用isoformat()创建了datetime对象,则可以简单地使用datetime.fromisoformat()
。
编辑2:
正如Mark Amery所指出的,我添加了一个尝试..异常块来处理缺少小数秒的情况。
datetime.fromisoformat()
来自动处理类似于输入字符串'2018-01-31T09:24:31.488670+00:00'
的日期时间格式。 - Martijn Pietersdatetime.fromisoformat()
和 datetime.isoformat()
。 - Andreas ProfousValueError: time data '2018-01-31T09:24:31.488670+00:00' does not match format '%Y-%m-%dT%H:%M:%S.%f%z'
,这是因为 %z
不匹配 +00:00
。然而,+0000
匹配 %z
,请参考 Python 文档 https://docs.python.org/3.6/library/datetime.html#strftime-and-strptime-behavior。 - Ericfromisoformat()
函数,现在它可以处理Z
时区标识符了。例如:datetime.fromisoformat('2018-01-31T09:24:31Z')
会返回datetime.datetime(2018, 1, 31, 9, 24, 31, tzinfo=datetime.timezone.utc)
。 - Martijn Pieters您收到的错误信息是什么?是否像以下内容?
>>> datetime.datetime.strptime("2008-08-12T12:20:30.656234Z", "%Y-%m-%dT%H:%M:%S.Z")
ValueError: time data did not match format: data=2008-08-12T12:20:30.656234Z fmt=%Y-%m-%dT%H:%M:%S.Z
如果是的话,您可以通过"."来拆分输入字符串,然后将微秒添加到获得的日期时间中。
试一下这个:
>>> def gt(dt_str):
dt, _, us= dt_str.partition(".")
dt= datetime.datetime.strptime(dt, "%Y-%m-%dT%H:%M:%S")
us= int(us.rstrip("Z"), 10)
return dt + datetime.timedelta(microseconds=us)
>>> gt("2008-08-12T12:20:30.656234Z")
datetime.datetime(2008, 8, 12, 12, 20, 30, 656234)
""
或 "Z"
,那么它必须是以小时/分钟为单位的偏移量,可以直接添加到/从日期时间对象中。你可以创建一个 tzinfo 子类来处理它,但这可能不是推荐的做法。 - SingleNegationEliminationdatetime.fromisoformat
,可以处理大多数ISO8601和RFC3339格式。https://docs.python.org/3.11/library/datetime.html#datetime.datetime.fromisoformat - Nelsonimport re
import datetime
s = "2008-09-03T20:56:35.450686Z"
d = datetime.datetime(*map(int, re.split(r'[^\d]', s)[:-1]))
datetime.datetime(*map(int, re.findall('\d+', s))
的翻译:日期时间模块中的一个变体,将字符串中的数字提取出来并转换为整数后作为参数传递给 datetime.datetime()
函数。 - jfs现在,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())