Come convalido un formato di stringa di data in Python?


143

Ho un metodo Python che accetta un input di data come stringa .

Come faccio ad aggiungere una convalida per assicurarmi che la stringa di data che viene passata al metodo sia nel file ffg. formato:

'YYYY-MM-DD'

in caso contrario, il metodo dovrebbe generare una sorta di errore


2
Potrebbe essere più Pythonic (chiedi perdono, non permesso) di non controllare affatto e cogliere eventuali eccezioni che si verificano.
Thomas

Risposte:


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
C'è un modo per farlo senza provare / tranne? Python tende a rallentare significativamente quando viene sollevata e rilevata un'eccezione.
Chiffa,

1
@chiffa Potresti abbinare un regex in formato data ma non è raccomandato perché è meno robusto e le eccezioni sono più chiare. Sei sicuro che la convalida della data sia il tuo collo di bottiglia?
jamylak,

1
Non proprio, quindi alla fine mi limiterò a gettare-tranne il costrutto in una funzione. Sono solo sorpreso dal fatto che non esiste alcuna funzione di convalida del ritorno bool che possa innescare il lancio di eccezione nella libreria datetime.
Chiffa,

@chiffa Forse non includevano apposta la funzione di validazione del ritorno bool, potrebbe esistere in librerie esterne
jamylak,

2
Per coloro che desiderano il riempimento zero nelle date, questa soluzione non funzionerà in quanto lo strptime non è rigoroso sul riempimento zero. Implementa una tua regex o controlla la lunghezza della stringa risultante dopo aver rimosso gli spazi bianchi e quindi fai uso di questa soluzione.
Suparshva,

66

La libreria Pythondateutil è progettata per questo (e altro). Lo converte automaticamente in un datetimeoggetto per te e genera un ValueErrorse non ci riesce.

Come esempio:

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

Ciò genera un ValueErrorse la data non è formattata correttamente:

>>> 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è inoltre estremamente utile se si inizia a analizzare altri formati in futuro, poiché può gestire in modo intelligente i formati più noti e consente di modificare le specifiche: dateutilanalisi degli esempi .

Gestisce anche i fusi orari se ne hai bisogno.

Aggiornamento basato sui commenti : parseaccetta anche l'argomento della parola chiave dayfirstche controlla se il giorno o il mese dovrebbe venire prima se una data è ambigua. L'impostazione predefinita è False. Per esempio

>>> 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
può accettare troppo, ad esempio, parse('13/12/2001')è "13 dic" ma parse('11/12/2001')è "12 nov" (il primo risultato suggerirebbe "11 dic" qui).
jfs,

2
parseaccetta in realtà un dayfirstargomento di parole chiave che ti consente di controllarlo. parse('11/12/2001', dayfirst=True)restituirà "11 dic." L'impostazione predefinita di dateutil èdayfirst=False
Jacinda,

ti manca il punto che datetutil.parser.parse()accetta troppi formati temporali (potresti trovare altri esempi con input ambigui). Se si desidera confermare che l'input è nel formato AAAA-MM-GG, la parse()funzione è lo strumento sbagliato.
jfs

1
Questo è un punto completamente valido: se vuoi davvero limitarti a quel formato specifico, questo non lo fa, e la risposta accettata fa già un ottimo lavoro nel fare la cosa giusta in quel caso. Penso che quando ho scritto la risposta stavo pensando di più sulla falsariga di come convalidare se fosse una data valida rispetto al particolare formato richiesto dall'autore, che quando le persone incontrano questa domanda è ciò che sono spesso cercando.
Jacinda,

C'è un modo per ottenere .parse()di restituire la stringa di formato oltre datetimeall'oggetto?
citynorman,

35

Penso che la funzione di validazione completa dovrebbe apparire così:

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

Eseguendo solo

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

non è sufficiente perché il metodo strptime non controlla che il mese e il giorno del mese siano numeri decimali con spaziatura zero. Per esempio

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

sarà eseguito senza errori.


3
"Sei tecnicamente corretto, il miglior tipo di corretto." Avevo bisogno di assicurarmi questo nelle mie corde.
delrocco,

Questo funziona bene contro i miei test, tuttavia io la documentazione sembra errata in quanto afferma: "% d -> Giorno del mese come un numero decimale con riempimento zero -> 01, 02, ..., 31" e lo stesso per% m -> Mese come numero decimale con spaziatura zero. -> 01, 02,…, 12 docs.python.org/2/library/…
thanos.a

Se è necessario verificare che il mese e il giorno siano a zero, non sarebbe sufficiente controllare solo la lunghezza della stringa e datetime.strptime(date_text, "%Y-%m-%d")?
Kyle Barron

17
from datetime import datetime

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

..questo genera un ValueErrorse riceve un formato incompatibile.

..se hai molto a che fare con date e ore (nel senso di oggetti datetime, al contrario di float di timestamp unix), è una buona idea guardare nel modulo pytz, e per storage / db, archiviare tutto in UTC .


2
Eri più veloce, l'avrei pubblicato io stesso ( ideone.com/vuxDDf ). Upvote.
Tadeck,

..ho appena visto subito dopo che è stato pubblicato, e sembra che stia funzionando con oggetti datetime oggi.
Mr. B

-7

Questo è il modo più semplice:

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

2
Sarebbe meglio avere una spiegazione, invece del solo codice.
lukas_o
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.