Як я підтверджую формат рядка дати в python?


143

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

Як додати перевірку, щоб переконатися, що рядок дати, переданий методу, знаходиться у ffg. формат:

'YYYY-MM-DD'

якщо це не так, метод повинен викликати якусь помилку


2
Можливо, більш пітонічним (просити пробачення, а не дозволу) може взагалі не перевіряти та виловлювати всі винятки, що виникають.
Томас

Відповіді:


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

8
Чи існує спосіб зробити це без спроби / за винятком? Python, як правило, значно сповільнюється, коли виняток і піднятий випадок.
chiffa

1
@chiffa Ви можете зіставити регулярний вимір формату дати, але його не рекомендується, оскільки він менш надійний, а винятки чіткіші. Ви впевнені, що перевірка дати - це вузьке місце?
jamylak

1
Насправді, тож, врешті-решт, я просто заверну кидок, окрім конструкції у функції. Я просто здивований, що в бібліотеці дат не існує функції підтвердження повернення, що повертається, яка би викликала викид винятків.
чиффа

@chiffa Можливо, вони не включили функцію підтвердження повернення bool за призначенням, вона може існувати у зовнішніх бібліотеках
jamylak

2
Для тих, хто хоче нульове набивання в датах, це рішення не працюватиме, оскільки strptime не є суворим щодо нульового набивання. Реалізуйте власний регулярний вираз або перевірте довжину результуючого рядка після зачистки пробілів, а потім скористайтеся цим рішенням.
Супаршва

65

Бібліотека 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

2
parseнасправді бере dayfirstаргумент ключового слова, що дозволяє вам це контролювати. parse('11/12/2001', dayfirst=True)повернеться "11 грудня" За замовчуванням dateutildayfirst=False
Jacinda

вам не вистачає точки, яка datetutil.parser.parse()приймає занадто багато форматів часу (ви можете знайти інші приклади з неоднозначним введенням). Якщо ви хочете перевірити, що ваш внесок у форматі РРРР-ММ-DD, то parse()функція є неправильним інструментом.
jfs

1
Це цілком справедливий момент - якщо ви дійсно хочете обмежитися лише певним форматом, цього не робити, і прийнята відповідь вже чудово справляється в тому, щоб зробити правильну справу в цьому випадку. Я думаю, що коли я написав відповідь, я більше думав, як вказати, як перевірити, чи це дійсна дата, а не конкретний формат, який запитував автор, і коли люди стикаються з цим питанням - це те, що вони часто шукаю.
Jacinda

Чи є спосіб отримати .parse()повернути рядок формату на додаток до datetimeоб'єкта?
citynorman

35

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

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

Якщо вам потрібно перевірити, що місяць і день прокладені нулями, чи не достатньо лише перевірити довжину рядка datetime.strptime(date_text, "%Y-%m-%d")?
Кайл Баррон

17
from datetime import datetime

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

..це підвищує показник, ValueErrorякщо він отримує несумісний формат.

..якщо ви багато маєте справу з датами та часом (у сенсі об'єктів datetime, на відміну від плаваючої часової позначки Unix), непогано заглянути в модуль pytz, а для зберігання / db зберігати все в UTC .


2
Ви були швидшими, я б сам розмістив це ( ideone.com/vuxDDf ). Оновлення
Тадек

.. просто бачив це одразу після його розміщення, і, мабуть, сьогодні працює з об’єктами datetime.
Містер Б

-7

Це найпростіший спосіб:

date = datetime.now()
date = date.strftime('%Y-%m-%d_%H-%M-%S.jpg')

2
Було б краще мати пояснення, а не лише код.
lukas_o
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.