在Python中验证ISO-8601日期时间字符串?

Ste*_*tew 4 python validation datetime iso8601 arrow-python

我想编写一个函数,该函数接受一个字符串并返回True一个有效的ISO-8601日期时间(精确到微秒,包括时区偏移量),False否则返回。

我发现其他 问题提供了不同的解析日期时间字符串的方式,但是我只想返回TrueISO-8601格式。除非对不匹配ISO-8601的格式抛出错误,否则解析不会对我有帮助。

(我在代码的其他地方使用了漂亮的箭头库。arrow欢迎使用该解决方案。)


编辑:似乎在通用Python日期时间包中不存在“此字符串是否为有效的ISO 8601日期时间”的常规解决方案。

因此,为了使这个问题更窄,更具体和可回答,我将选择一种格式字符串,该格式字符串将验证以下格式的日期时间字符串:

'2016-12-13T21:20:37.593194+00:00'
Run Code Online (Sandbox Code Playgroud)

目前,我正在使用:

format_string = '%Y-%m-%dT%H:%M:%S.%f%z'
datetime.datetime.strptime(my_timestamp, format_string)
Run Code Online (Sandbox Code Playgroud)

这给出:

ValueError: time data '2016-12-13T21:20:37.593194+00:00' does not match format '%Y-%m-%dT%H:%M:%S.%f%z'
Run Code Online (Sandbox Code Playgroud)

问题似乎在于UTC偏移(+00:00)中的冒号。如果我使用不带冒号的偏移量(例如'2016-12-13T21:20:37.593194+0000'),则可以按预期正确解析。显然,这是因为datetime%z令牌不尊重带有冒号的UTC偏移量格式,只有不包含冒号的格式,即使这两个规范均有效

Han*_*ter 9

最近版本的 Python(从 3.7 开始)fromisoformat()datetime标准库中有一个函数。请参阅:https : //docs.python.org/3.7/library/datetime.html

所以这将解决问题:

from datetime import datetime

def datetime_valid(dt_str):
    try:
        datetime.fromisoformat(dt_str)
    except:
        return False
    return True
Run Code Online (Sandbox Code Playgroud)

更新:

我了解到 Python 无法将“Z”后缀识别为有效。因为我想在我的 API 中支持这一点,所以我现在使用:

from datetime import datetime

def datetime_valid(dt_str):
    try:
        datetime.fromisoformat(dt_str)
    except:
        try:
            datetime.fromisoformat(dt_str.replace('Z', '+00:00'))
        except:
            return False
        return True
    return True
Run Code Online (Sandbox Code Playgroud)

  • 我认为你可以只使用“.replace”版本,因为 iso 字符串中的其他任何地方都不应该有“Z”? (2认同)

小智 7

https://www.safaribooksonline.com/library/view/regular-expressions-cookbook/9781449327453/ch04s07.html

以ISO8601格式提供许多变体来验证日期和时间(例如2008-08-30T01:45:36或2008-08-30T01:45:36.123Z)。XML模式dateTime类型的正则表达式为:

>>> regex = r'^(-?(?:[1-9][0-9]*)?[0-9]{4})-(1[0-2]|0[1-9])-(3[01]|0[1-9]|[12][0-9])T(2[0-3]|[01][0-9]):([0-5][0-9]):([0-5][0-9])(\.[0-9]+)?(Z|[+-](?:2[0-3]|[01][0-9]):[0-5][0-9])?$'
Run Code Online (Sandbox Code Playgroud)

因此,为了验证您可以执行以下操作:

>>> import re
>>> match_iso8601 = re.compile(regex).match
>>> def validate_iso8601(str_val):
...     try:            
...         if match_iso8601( str_val ) is not None:
...             return True
...     except:
...         pass
...     return False
Run Code Online (Sandbox Code Playgroud)

一些例子:

>>> validate_iso8601('2017-01-01')
False

>>> validate_iso8601('2008-08-30T01:45:36.123Z')
True

>>> validate_iso8601('2016-12-13T21:20:37.593194+00:00')
True
Run Code Online (Sandbox Code Playgroud)

  • 请注意,它不检查日期是否存在。例如,“2019-02-29T12:00:00+00:00”不是有效的 iso 日期,但您的代码会说它没问题。 (3认同)

Mar*_*som 0

考虑到您对问题施加的约束,您可以使用正则表达式轻松解决它。

>>> import re
>>> re.match(r'^\d{4}-\d\d-\d\dT\d\d:\d\d:\d\d\.\d{6}[+-]\d\d:\d\d$', '2016-12-13T21:20:37.593194+00:00')
<_sre.SRE_Match object; span=(0, 32), match='2016-12-13T21:20:37.593194+00:00'>
Run Code Online (Sandbox Code Playgroud)

如果您需要通过ISO 8601 的所有变体,这将是一个更加复杂的正则表达式,但仍然可以完成。如果您还需要验证数字范围,例如验证小时是否在 0 到 23 之间,您可以将括号放入正则表达式中以创建匹配组,然后验证每个组。