190 votes

Comment valider un format de chaîne de date en python ?

J'ai une méthode python qui accepte une date saisie sous forme de chaîne .

Comment puis-je ajouter une validation pour m'assurer que la chaîne de date transmise à la méthode est au bon format ?

'YYYY-MM-DD'

si ce n'est pas le cas, la méthode devrait soulever une sorte d'erreur

301voto

jamylak Points 38094
>>> 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

90voto

Jacinda Points 1575

El Python dateutil est conçue pour cela (et plus encore). Elle le convertira automatiquement en un datetime pour vous et soulève un ValueError si elle ne peut pas.

A titre d'exemple :

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

Cela soulève une ValueError si la date n'est pas formatée correctement :

>>> 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 est également extrêmement utile si vous avez besoin d'analyser d'autres formats à l'avenir, car il peut gérer intelligemment la plupart des formats connus et vous permet de modifier votre spécification : dateutil exemples d'analyse syntaxique .

Il gère également les fuseaux horaires si vous en avez besoin.

Mise à jour sur la base des commentaires : parse accepte également l'argument mot-clé dayfirst qui contrôle si le jour ou le mois est censé venir en premier si une date est ambiguë. La valeur par défaut est False. Par exemple

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

56voto

Eduard Stepanov Points 1013

Je pense que la fonction de validation complète devrait ressembler à ceci :

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

Exécuter juste

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

n'est pas suffisant car la méthode strptime ne vérifie pas que le mois et le jour du mois sont des nombres décimaux complétés par des zéros. Par exemple

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

sera exécuté sans erreur.

21voto

Brian Visel Points 473
from datetime import datetime

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

cela soulève une ValueError s'il reçoit un format incompatible.

si vous manipulez beaucoup de dates et d'heures (dans le sens d'objets de type datetime, par opposition à des flottants de type timestamp unix), c'est une bonne idée de regarder le module pytz, et pour le stockage/db, de tout stocker en UTC.

3voto

Gergely M Points 75

Par simple curiosité, j'ai chronométré les deux réponses concurrentes postées ci-dessus.
Et j'ai eu les résultats suivants :

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

Et voici le code que j'ai utilisé (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))

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X