Jak sprawdzić poprawność formatu ciągu daty w Pythonie?


143

Mam metodę Pythona, która akceptuje dane wejściowe jako ciąg .

Jak dodać walidację, aby upewnić się, że ciąg daty przekazywany do metody znajduje się w pliku ffg. format:

'YYYY-MM-DD'

jeśli tak nie jest, metoda powinna wywołać jakiś błąd


2
Może być bardziej Pythonic (poproś o wybaczenie, a nie pozwolenie), aby w ogóle nie sprawdzać i wychwytywać wszelkie wynikające z tego wyjątki, które wystąpią.
— Thomas

Odpowiedzi:


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
Czy można to zrobić bez próby / z wyjątkiem? Python ma tendencję do znacznego spowolnienia, gdy wyjątek jest zgłaszany i przechwytywany.
— chiffa

1
@chiffa Możesz dopasować wyrażenie regularne w formacie daty, ale nie jest to zalecane, ponieważ jest mniej niezawodne, a wyjątki są wyraźniejsze. Czy na pewno walidacja daty jest Twoim wąskim gardłem?
— jamylak

1
Niezupełnie, więc na koniec po prostu zawijam konstrukcję rzutowania z wyjątkiem funkcji. Jestem po prostu zaskoczony, że nie ma funkcji walidującej zwracającej wartość bool, która wyzwoliłaby rzut wyjątku w bibliotece datetime.
— chiffa

@chiffa Może celowo nie uwzględnili funkcji bool zwracającej funkcję walidacji, może ona istnieć w bibliotekach zewnętrznych
— jamylak

2
Dla tych, którzy chcą dopełnienia zerami w datach, to rozwiązanie nie zadziała, ponieważ strptime nie wymaga ścisłego uzupełniania zer. Zaimplementuj własne wyrażenie regularne lub sprawdź długość powstałego ciągu znaków po usunięciu białych znaków, a następnie skorzystaj z tego rozwiązania.
— Suparshva

65

Pythondateutil biblioteka jest przeznaczony do tego (i więcej). Automatycznie przekształci to w datetimeobiekt dla ciebie i podniesie, ValueErrorjeśli nie może.

Jako przykład:

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

Wiąże się ValueErrorto z nieprawidłowym formatowaniem daty:

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

dateutiljest również niezwykle przydatny, jeśli w przyszłości będziesz musiał analizować inne formaty, ponieważ może inteligentnie obsługiwać większość znanych formatów i umożliwia modyfikowanie specyfikacji: dateutilanalizowanie przykładów .

Obsługuje również strefy czasowe, jeśli tego potrzebujesz.

Aktualizacja oparta na komentarzach : parseakceptuje również argument słowa kluczowego, dayfirstktóry kontroluje, czy dzień lub miesiąc ma być pierwszy, jeśli data jest niejednoznaczna. Domyślnie jest to False. Na przykład

>>> 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
może przyjąć za dużo, np. parse('13/12/2001')„13 grudnia”, ale parse('11/12/2001')„12 listopada” (pierwszy wynik sugerowałby tutaj „11 grudnia”).
— jfs

2
parsew rzeczywistości przyjmuje dayfirstargument słowa kluczowego, który pozwala ci to kontrolować. parse('11/12/2001', dayfirst=True)zwróci „11 grudnia”. Dateutil domyślnie todayfirst=False
— Jacinda

brakuje Ci punktu, który datetutil.parser.parse()akceptuje zbyt wiele formatów czasu (możesz znaleźć inne przykłady z niejednoznacznymi danymi wejściowymi). Jeśli chcesz sprawdzić , czy wprowadzone dane są w formacie RRRR-MM-DD, parse()funkcja jest niewłaściwym narzędziem.
— jfs

1
To całkowicie słuszna uwaga - jeśli naprawdę chcesz ograniczyć się tylko do tego konkretnego formatu, to tego nie robi, a zaakceptowana odpowiedź już robi świetną robotę, robiąc właściwą rzecz w tym przypadku. Myślę, że kiedy pisałem odpowiedź, myślałem bardziej o wskazaniu, jak sprawdzić, czy była to ważna data, w przeciwieństwie do konkretnego formatu, o który prosił autor, który, gdy ludzie napotykają to pytanie, jest tym, co często szukam.
— Jacinda

Czy istnieje sposób na .parse()zwrócenie ciągu formatu oprócz datetimeobiektu?
— citynorman

35

Myślę, że pełna funkcja walidacji powinna wyglądać tak:

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

Wykonywanie tylko

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

nie wystarczy, ponieważ metoda strptime nie sprawdza, czy miesiąc i dzień miesiąca są liczbami dziesiętnymi uzupełnionymi zerami. Na przykład

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

zostanie wykonany bez błędów.


3
„Jesteś poprawny technicznie - najlepszy rodzaj poprawności”. Musiałem to zapewnić w moich strunach.
— delrocco

Działa to dobrze w przypadku moich testów, jednak dokumentacja wydaje się niepoprawna, ponieważ stwierdza: "% d -> Dzień miesiąca jako liczba dziesiętna z zerami -> 01, 02,…, 31" i to samo dla% m -> Miesiąc jako liczba dziesiętna z zerami. -> 01, 02,…, 12 docs.python.org/2/library/…
— thanos.a

Jeśli chcesz sprawdzić, czy miesiąc i dzień są wypełnione zerami, czy nie wystarczyłoby po prostu sprawdzić długość ciągu i datetime.strptime(date_text, "%Y-%m-%d")?
— Kyle Barron

17
from datetime import datetime

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

.. wywołuje to, ValueErrorjeśli otrzyma niezgodny format.

..jeśli masz do czynienia z datami i czasami (w sensie obiektów datetime, w przeciwieństwie do unx timestamp float), dobrym pomysłem jest zajrzenie do modułu pytz i przechowywanie / db, przechowywanie wszystkiego w UTC .


2
Byłeś szybszy, sam bym to opublikował ( ideone.com/vuxDDf ). Głosuj za.
— Tadeck

.. po prostu zobaczyłem to zaraz po opublikowaniu i akurat dzisiaj pracowałem z obiektami datetime.
— Pan B

-7

To najłatwiejszy sposób:

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

2
Lepiej byłoby mieć wyjaśnienie zamiast samego kodu.
— lukas_o
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.