Как мне проверить формат строки даты в Python?

148

У меня есть метод python, который принимает ввод даты в виде строки .

Как добавить проверку, чтобы убедиться, что строка даты, передаваемая методу, находится в файле ffg. формат:

'YYYY-MM-DD'

если это не так, метод должен вызвать какую-то ошибку

код
источник
2
Это может быть более Pythonic (просить прощения, а не разрешения) вообще не проверять и улавливать любые возникающие в результате исключения.
Thomas

Ответы:

239
>>> 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
Джамылак
источник
9
Есть ли способ сделать это без попытки / кроме? Python имеет тенденцию значительно замедляться при возникновении и перехвате исключения.
chiffa 06
1
@chiffa Вы можете сопоставить регулярное выражение формата даты, но это не рекомендуется, потому что оно менее надежно, а исключения более понятны. Вы уверены, что проверка даты является вашим узким местом?
jamylak 06
1
Не совсем, так что в конце я просто оберну конструкцию throw-except в функцию. Я просто удивлен, что в библиотеке datetime нет функции проверки, возвращающей bool, которая запускала бы исключение Exception.
chiffa
3
Для тех, кто хочет нулевого заполнения в датах, это решение не будет работать, поскольку strptime не строго придерживается нулевого заполнения. Реализуйте собственное регулярное выражение или проверьте длину результирующей строки после удаления пробелов, а затем воспользуйтесь этим решением.
ร ย ק ค г ร ђ ש ค
1
Да, согласен с @Suparshva. Например, эта строка будет считаться правильной датой без ValueError: «2018-10-1»
zen11625
70

Библиотека Pythondateutil предназначена для этого (и не только). Он автоматически преобразует это в datetimeобъект для вас и поднимет, ValueErrorесли не может.

Например:

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

Это вызывает ошибку, 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

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
Джасинда
источник
1
он может принимать слишком много, например, parse('13/12/2001')«13 декабря», но parse('11/12/2001')«12 ноября» (первый результат здесь предполагает «11 декабря»).
jfs
3
parseфактически принимает dayfirstаргумент ключевого слова, который позволяет вам контролировать это. parse('11/12/2001', dayfirst=True)вернет "11 дек." по умолчанию dateutil являетсяdayfirst=False
Jacinda
вам не хватает точки, которая datetutil.parser.parse()принимает слишком много форматов времени (вы можете найти другие примеры с неоднозначным вводом). Если вы хотите убедиться, что введенные вами данные находятся в формате ГГГГ-ММ-ДД, parse()функция - неправильный инструмент.
jfs
1
Это совершенно верный момент - если вы действительно хотите ограничиться только этим конкретным форматом, этого не произойдет, а принятый ответ уже отлично справляется с правильными действиями в этом случае. Думаю, когда я писал ответ, я больше думал о том, чтобы указать, как проверить, действительна ли это дата, в отличие от конкретного формата, запрошенного автором, и когда люди сталкиваются с этим вопросом, они часто находясь в поиске.
Джасинда
Есть ли способ .parse()вернуть строку формата в дополнение к datetimeобъекту?
citynorman 05
39

Я думаю, что полная функция проверки должна выглядеть так:

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

будет выполнено без ошибок.

Эдуард Степанов
источник
3
«Вы технически правы - лучший вид правильного». Мне нужно было убедиться в этом в своих струнах.
delrocco
Это отлично работает с моими тестами, однако документация кажется неверной, поскольку в ней говорится: «% d -> День месяца как десятичное число с нулевым дополнением -> 01, 02,…, 31» и то же самое для% m -> Месяц в виде десятичного числа с нулями. -> 01, 02,…, 12 docs.python.org/2/library/…
thanos.a
2
Если вам нужно проверить, что месяц и день заполнены нулями, разве не достаточно просто проверить длину строки и datetime.strptime(date_text, "%Y-%m-%d")?
Кайл Бэррон,
17
from datetime import datetime

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

..это вызывает ошибку, ValueErrorесли он получает несовместимый формат.

..если вы много имеете дело с датами и временем (в смысле объектов datetime, в отличие от плавающих меток времени unix), неплохо было бы заглянуть в модуль pytz, а для storage / db хранить все в UTC .

Мистер Б.
источник
2
Ты был быстрее, я бы сам выложил ( ideone.com/vuxDDf ). Голосовать за.
Tadeck 01
.. только что увидел это сразу после того, как он был опубликован, и сегодня работал с объектами datetime.
Mr. B
-7

Это самый простой способ:

date = datetime.now()
date = date.strftime('%Y-%m-%d_%H-%M-%S.jpg')
Тимор
источник
2
Лучше было бы объяснение, а не только код.
lukas_o