186

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

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

'YYYY-MM-DD'

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

4

5 回答 5

290
>>> 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
于 2013-06-01T08:23:42.447 回答
86

Pythondateutil库是为此(以及更多)而设计的。它会自动将其转换为您的对象,如果不能datetime,则引发 a 。ValueError

举个例子:

>>> from dateutil.parser import parse
>>> parse("2003-09-25")
datetime.datetime(2003, 9, 25, 0, 0)

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

>>> 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

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
于 2013-06-01T08:21:42.650 回答
50

我认为完整的验证功能应该是这样的:

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

只执行

datetime.strptime(date_text, "%Y-%m-%d") 

还不够,因为 strptime 方法不会检查月份和月份中的日期是否是零填充的十进制数字。例如

datetime.strptime("2016-5-3", '%Y-%m-%d')

将在没有错误的情况下执行。

于 2016-05-05T08:10:16.623 回答
19
from datetime import datetime

datetime.strptime(date_string, "%Y-%m-%d")

ValueError..如果收到不兼容的格式,则会引发 a 。

..如果您经常处理日期和时间(在日期时间对象的意义上,而不是 unix 时间戳浮点数),最好查看 pytz 模块,对于 storage/db,将所有内容存储在 UTC .

于 2013-06-01T08:22:18.063 回答
2

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

dateutil.parser (valid str): 4.6732222699938575
dateutil.parser (invalid str): 1.7270505399937974
datetime.strptime (valid): 0.7822393209935399
datetime.strptime (invalid): 0.4394566189876059

这是我使用的代码(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))
于 2021-01-26T16:05:08.703 回答