如何要求在 Python 验证期间将时间戳补零?

How to require a timestamp to be zero-padded during validation in Python?

我正在尝试验证一个字符串,该字符串应该包含格式为 ISO 8601 的时间戳(通常用于 JSON)。

Python 的 strptime 在验证零填充方面似乎非常宽容,请参见下面的代码示例(请注意小时缺少前导零):

>>> import datetime
>>> s = '1985-08-23T3:00:00.000'
>>> datetime.datetime.strptime(s, '%Y-%m-%dT%H:%M:%S.%f')
datetime.datetime(1985, 8, 23, 3, 0)

例如,它优雅地接受一个小时未被零填充的字符串,并且不会像我期望的那样抛出 ValueError 异常。

有什么方法可以强制 strptime 验证它是否被零填充?或者 Python 的标准库中是否还有其他内置函数?

我想避免为此编写自己的 regexp

要强制 strptime 为您验证前导零,您必须将自己的文字添加到 Python 的 _strptime._TimeRE_cache。该解决方案非常 hacky,很可能不是很便携,并且需要编写 RegEx - 尽管只是时间戳的小时部分。

该问题的另一种解决方案是编写您自己的函数,该函数使用 strptime 并将解析的日期转换回字符串并比较这两个字符串。此解决方案是可移植的,但它缺乏明确的错误消息 - 您将无法区分小时、分钟、秒中缺少的前导零。

除了弄乱 Python 内部结构之外,我唯一能想到的就是通过了解您要查找的内容来测试格式的有效性。

所以,如果我猜对了,格式是 '%Y-%m-%dT%H:%M:%S.%f' 并且应该用零填充。 然后,您知道要查找的字符串的确切长度并重现预期结果..

import datetime
s = '1985-08-23T3:00:00.000'

stripped = datetime.datetime.strptime(s, '%Y-%m-%dT%H:%M:%S.%f') 
try:
    assert len(s) == 23
except AssertionError:
    raise ValueError("time data '{}' does not match format '%Y-%m-%dT%H:%M:%S.%f".format(s))
else:
    print(stripped) #just for good measure

>>ValueError: time data '1985-08-23T3:00:00.000' does not match format '%Y-%m-%dT%H:%M:%S.%f

你说你想避免使用正则表达式,但这实际上是适合使用正则表达式的问题类型。正如您所发现的,strptime 对于接受的输入非常灵活。但是,这个问题的正则表达式比较容易编写:

import re

date_pattern = re.compile(r'\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}.\d{3}')
s_list = [
    '1985-08-23T3:00:00.000',
    '1985-08-23T03:00:00.000'
]
for s in s_list:
    if date_pattern.match(s):
        print "%s is valid" % s
    else:
        print "%s is invalid" % s

输出

1985-08-23T3:00:00.000 is invalid
1985-08-23T03:00:00.000 is valid

repl.it

上试用

已经有一个答案,用 Python strptime() 解析 ISO8601 或 RFC3339 date/time 是不可能的:How to parse an ISO 8601-formatted date? 所以,为了回答你的问题,标准 Python 库中没有办法可靠地解析这样的日期。 关于正则表达式建议,日期字符串如

2020-14-32T45:33:44.123

将生成有效日期。有很多 Python 模块(如果您在 https://pypi.python.org 上搜索 "iso8601"),但是构建 complete ISO8601 验证器需要闰秒之类的东西、可能的时区偏移值列表等等。