如何在python中验证日期字符串格式?

cod*_*ode 118 python date

我有一个python方法接受日期输入作为字符串.

如何添加验证以确保传递给方法的日期字符串位于ffg中.格式:

'YYYY-MM-DD'
Run Code Online (Sandbox Code Playgroud)

如果不是,方法应该引发某种错误

jam*_*lak 187

>>> import datetime
>>> def validate(date_text):
    try:
        datetime.datetime.strptime(date_text, '%Y-%m-%d')
    except ValueError:
        raise ValueError("Incorrect data format, should be YYYY-MM-DD")


>>> validate('2003-12-23')
>>> validate('2003-12-32')

Traceback (most recent call last):
  File "<pyshell#20>", line 1, in <module>
    validate('2003-12-32')
  File "<pyshell#18>", line 5, in validate
    raise ValueError("Incorrect data format, should be YYYY-MM-DD")
ValueError: Incorrect data format, should be YYYY-MM-DD
Run Code Online (Sandbox Code Playgroud)

  • 没有尝试/除外,有没有办法做到这一点?当异常被引发并被捕获时,Python往往会显着减慢速度. (5认同)
  • 对于那些希望在日期中填充零的人,此解决方案将不起作用,因为 strptime 对零填充并不严格。实现您自己的正则表达式或在去除空格后检查结果字符串的长度,然后使用此解决方案。 (3认同)
  • 不是真的,所以最后我将把 throw-except 构造包装在一个函数中。我只是感到惊讶的是,没有返回 bool 的验证函数会触发日期时间库中的异常抛出。 (2认同)

Jac*_*nda 58

Python的dateutil库是专门为这个(及以上).它会自动将其转换为datetime对象,ValueError如果不能,则自动转换为对象.

举个例子:

>>> from dateutil.parser import parse
>>> parse("2003-09-25")
datetime.datetime(2003, 9, 25, 0, 0)
Run Code Online (Sandbox Code Playgroud)

ValueError如果日期格式不正确,则会引发:

>>> parse("2003-09-251")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/Users/jacinda/envs/dod-backend-dev/lib/python2.7/site-packages/dateutil/parser.py", line 720, in parse
    return DEFAULTPARSER.parse(timestr, **kwargs)
  File "/Users/jacinda/envs/dod-backend-dev/lib/python2.7/site-packages/dateutil/parser.py", line 317, in parse
    ret = default.replace(**repl)
ValueError: day is out of range for month
Run Code Online (Sandbox Code Playgroud)

dateutil如果您将来开始需要解析其他格式,它也非常有用,因为它可以智能地处理大多数已知格式并允许您修改规范:dateutil解析示例.

如果您需要,它还可以处理时区.

基于注释更新:parse还接受关键字参数dayfirst,该参数控制日期或月份是否预期在日期不明确的情况下首先出现.默认为False.例如

>>> parse('11/12/2001')
>>> datetime.datetime(2001, 11, 12, 0, 0) # Nov 12
>>> parse('11/12/2001', dayfirst=True)
>>> datetime.datetime(2001, 12, 11, 0, 0) # Dec 11
Run Code Online (Sandbox Code Playgroud)

  • 它可能接受太多,例如,“parse('13/12/2001')”是“13 Dec”,但“parse('11/12/2001')”是“12 Nov”(第一个结果会建议“11十二月”在这里)。 (2认同)
  • 实际上,“ parse”带有一个“ dayfirst”关键字参数,可以用来控制它。`parse('11 / 12/2001',dayfirst = True)`将返回“ 12月11日”。dateutil的默认值为`dayfirst = False` (2认同)
  • 您忽略了“datetutil.parser.parse()”接受太多时间格式的这一点(您可以找到其他输入不明确的示例)。如果您想“验证”您的输入是否采用 YYYY-MM-DD 格式,那么“parse()”函数是错误的工具。 (2认同)
  • 这是一个完全有效的观点 - 如果您真的想仅限于该特定格式,则不会这样做,并且在这种情况下,已接受的答案在做正确的事情方面已经做得很好。我认为当我写答案时,我更多地考虑指出如何验证它是否是有效日期,而不是作者要求的特定格式,当人们遇到这个问题时,他们经常会遇到这种情况寻找。 (2认同)

小智 24

我认为完整的验证功能应如下所示:

from datetime import datetime

def validate(date_text):
    try:
        if date_text != datetime.strptime(date_text, "%Y-%m-%d").strftime('%Y-%m-%d'):
            raise ValueError
        return True
    except ValueError:
        return False
Run Code Online (Sandbox Code Playgroud)

执行正常

datetime.strptime(date_text, "%Y-%m-%d") 
Run Code Online (Sandbox Code Playgroud)

是不够的,因为strptime方法不检查月份和月份是零填充十进制数.例如

datetime.strptime("2016-5-3", '%Y-%m-%d')
Run Code Online (Sandbox Code Playgroud)

将被执行而没有错误.

  • "你在技术上是正确的 - 最好的正确." 我需要在我的琴弦中确保这一点. (3认同)
  • 如果您需要检查月份和日期是否以零填充,那么仅检查字符串和“datetime.strptime(date_text, "%Y-%m-%d")”的长度是否就足够了? (3认同)

Mr.*_*. B 16

from datetime import datetime

datetime.strptime(date_string, "%Y-%m-%d")
Run Code Online (Sandbox Code Playgroud)

ValueError..如果它收到不兼容的格式,它会引发一个.

..如果你正在处理日期和时间很多(在日期时间对象的意义上,而不是unix时间戳浮点数),最好查看pytz模块,对于存储/数据库,将所有内容存储在UTC中.

  • 你速度更快,我会自己发布(http://ideone.com/vuxDDf).给予好评. (2认同)

Ger*_*y M 5

出于好奇,我对上面发布的两个相互竞争的答案进行了计时。
我得到了以下结果:

dateutil.parser (valid str): 4.6732222699938575
dateutil.parser (invalid str): 1.7270505399937974
datetime.strptime (valid): 0.7822393209935399
datetime.strptime (invalid): 0.4394566189876059
Run Code Online (Sandbox Code Playgroud)

这是我使用的代码(Python 3.6)


from dateutil import parser as date_parser
from datetime import datetime
from timeit import timeit


def is_date_parsing(date_str):
    try:
        return bool(date_parser.parse(date_str))
    except ValueError:
        return False


def is_date_matching(date_str):
    try:
        return bool(datetime.strptime(date_str, '%Y-%m-%d'))
    except ValueError:
        return False



if __name__ == '__main__':
    print("dateutil.parser (valid date):", end=' ')
    print(timeit("is_date_parsing('2021-01-26')",
                 setup="from __main__ import is_date_parsing",
                 number=100000))

    print("dateutil.parser (invalid date):", end=' ')
    print(timeit("is_date_parsing('meh')",
                 setup="from __main__ import is_date_parsing",
                 number=100000))

    print("datetime.strptime (valid date):", end=' ')
    print(timeit("is_date_matching('2021-01-26')",
                 setup="from __main__ import is_date_matching",
                 number=100000))

    print("datetime.strptime (invalid date):", end=' ')
    print(timeit("is_date_matching('meh')",
                 setup="from __main__ import is_date_matching",
                 number=100000))
Run Code Online (Sandbox Code Playgroud)