Wie überprüfe ich ein Datumszeichenfolgenformat in Python?

143

Ich habe eine Python-Methode, die eine Datumseingabe als Zeichenfolge akzeptiert .

Wie füge ich eine Validierung hinzu, um sicherzustellen, dass sich die an die Methode übergebene Datumszeichenfolge in der ffg befindet? Format:

'YYYY-MM-DD'

Wenn dies nicht der Fall ist, sollte die Methode einen Fehler auslösen

codemickeycode
quelle
2
Es könnte pythonischer sein (um Vergebung bitten, nicht um Erlaubnis), überhaupt nicht zu prüfen und alle daraus resultierenden Ausnahmen abzufangen.
Thomas
Verwandte: Wie kann
Kenorb

Antworten:

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
Jamylak
quelle
8
Gibt es eine Möglichkeit, dies ohne einen Versuch / außer zu tun? Python verlangsamt sich erheblich, wenn eine Ausnahme ausgelöst und abgefangen wird.
Chiffa
1
@chiffa Sie könnten mit einem regulären Datumsformat übereinstimmen, dies wird jedoch nicht empfohlen, da es weniger robust ist und Ausnahmen klarer sind. Sind Sie sicher, dass die Datumsüberprüfung Ihr Engpass ist?
Jamylak
1
Nicht wirklich, also werde ich am Ende nur das Throw-Except-Konstrukt in eine Funktion einschließen. Ich bin nur überrascht, dass es keine bool-return-validierende Funktion gibt, die den Exception-Wurf in der datetime-Bibliothek auslösen würde.
Chiffa
@chiffa Vielleicht haben sie Bool nicht absichtlich Validierungsfunktion zurückgegeben, es könnte in externen Bibliotheken existieren
Jamylak
2
Für diejenigen, die kein Auffüllen von Daten wünschen, funktioniert diese Lösung nicht, da die Strptime das Auffüllen von Null nicht streng regelt. Implementieren Sie einen eigenen regulären Ausdruck oder überprüfen Sie die Länge der resultierenden Zeichenfolge, nachdem Sie Leerzeichen entfernt haben, und verwenden Sie dann diese Lösung.
Suparshva
65

Die Python-dateutil Bibliothek ist dafür (und mehr) konzipiert. Es konvertiert dies automatisch in ein datetimeObjekt für Sie und löst ein aus, ValueErrorwenn dies nicht möglich ist.

Als Beispiel:

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

Dies löst ein aus, ValueErrorwenn das Datum nicht richtig formatiert ist:

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

dateutilDies ist auch äußerst nützlich, wenn Sie in Zukunft andere Formate analysieren müssen, da es die meisten bekannten Formate intelligent verarbeiten kann und Sie Ihre Spezifikation ändern können: dateutilAnalysebeispiele .

Es behandelt auch Zeitzonen, wenn Sie das brauchen.

Aktualisierung basierend auf Kommentaren : parseAkzeptiert auch das Schlüsselwortargument, dayfirstdas steuert, ob der Tag oder der Monat an erster Stelle stehen soll, wenn ein Datum nicht eindeutig ist. Dies ist standardmäßig False. Z.B

>>> 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
Jacinda
quelle
1
es kann zu viel akzeptieren, z. B. parse('13/12/2001')ist "13 Dec", aber parse('11/12/2001')ist "12 Nov" (das erste Ergebnis würde hier "11 Dec" vorschlagen).
JFS
2
parseTatsächlich wird ein dayfirstSchlüsselwortargument verwendet, mit dem Sie dies steuern können. parse('11/12/2001', dayfirst=True)wird "11 Dec." Die Standardeinstellung von dateutil istdayfirst=False
Jacinda
Ihnen fehlt der Punkt, der datetutil.parser.parse()zu viele Zeitformate akzeptiert (Sie könnten andere Beispiele mit mehrdeutiger Eingabe finden). Wenn Sie möchten bestätigen , dass Ihre Eingabe in YYYY-MM-DD - Format dann das parse()ist Funktion das falsche Werkzeug.
JFS
1
Das ist ein völlig gültiger Punkt - wenn Sie sich wirklich auf genau dieses Format beschränken möchten, funktioniert dies nicht, und die akzeptierte Antwort leistet in diesem Fall bereits hervorragende Arbeit, um das Richtige zu tun. Ich denke, als ich die Antwort schrieb, dachte ich eher daran, herauszufinden, wie man validiert, ob es sich um ein gültiges Datum handelt, als um das vom Autor angeforderte Format. Wenn Leute auf diese Frage stoßen, sind sie es oft Auf der Suche nach.
Jacinda
Gibt es eine Möglichkeit, .parse()die Formatzeichenfolge zusätzlich zum datetimeObjekt zurückzugeben?
Citynorman
35

Ich denke, die vollständige Validierungsfunktion sollte folgendermaßen aussehen:

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

Nur ausführen

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

ist nicht genug, da die strptime-Methode nicht überprüft, ob Monat und Tag des Monats mit Nullen aufgefüllte Dezimalzahlen sind. Beispielsweise

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

wird fehlerfrei ausgeführt.

Eduard Stepanov
quelle
3
"Sie sind technisch korrekt - die beste Art von richtig." Ich musste das in meinen Saiten sicherstellen.
Delrocco
Dies funktioniert gut gegen meine Tests, jedoch scheint die Dokumentation falsch zu sein, da sie besagt: "% d -> Tag des Monats als null aufgefüllte Dezimalzahl -> 01, 02, ..., 31" und dasselbe für% m -> Monat als null aufgefüllte Dezimalzahl. -> 01, 02,…, 12 docs.python.org/2/library/…
thanos.a
Wenn Sie überprüfen müssen, ob Monat und Tag mit Nullen aufgefüllt sind, reicht es dann nicht aus, nur die Länge der Zeichenfolge zu überprüfen und datetime.strptime(date_text, "%Y-%m-%d")?
Kyle Barron
17
from datetime import datetime

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

..dies löst ein aus, ValueErrorwenn es ein inkompatibles Format empfängt.

..wenn Sie sich häufig mit Datums- und Uhrzeitangaben beschäftigen (im Sinne von Datums- / Uhrzeitobjekten im Gegensatz zu Unix-Zeitstempel-Floats), ist es eine gute Idee, in das Pytz-Modul zu schauen und für Speicher / Datenbank alles in UTC zu speichern .

Herr B.
quelle
2
Du warst schneller, ich hätte es selbst gepostet ( ideone.com/vuxDDf ). Upvote.
Tadeck
Ich habe es gerade gesehen, nachdem es veröffentlicht wurde, und habe heute zufällig mit Datetime-Objekten gearbeitet.
Herr B
-7

Dies ist der einfachste Weg:

date = datetime.now()
date = date.strftime('%Y-%m-%d_%H-%M-%S.jpg')
TimorEranAV
quelle
2
Es wäre besser, eine Erklärung zu haben, anstatt nur Code.
lukas_o