Ich finde es merkwürdig, dass die naheliegendste Art, Date
Objekte in Java zu erstellen , veraltet ist und anscheinend durch einen nicht so offensichtlichen, nachsichtigen Kalender ersetzt wurde.
Wie überprüfen Sie, ob ein Datum, das als Kombination aus Tag, Monat und Jahr angegeben wird, ein gültiges Datum ist?
Zum Beispiel wäre der 31.02.2008 (wie in JJJJ-MM-TT) ein ungültiges Datum.
java
validation
calendar
date
Bloodboiler
quelle
quelle
Antworten:
Derzeit wird die Kalenderklasse verwendet. Es verfügt über die setLenient- Methode, die das Datum und den Auslöser sowie die Ausnahme überprüft , wenn sie außerhalb des Bereichs liegt, wie in Ihrem Beispiel.
Das Hinzufügen wurde vergessen: Wenn Sie eine Kalenderinstanz erhalten und die Uhrzeit anhand Ihres Datums festlegen, erhalten Sie auf diese Weise die Validierung.
quelle
java.util.Date
,java.util.Calendar
undjava.text.SimpleDateFormat
sind jetzt Erbe , durch die verdrängte java.time Klassen in Java gebaut 8 und höher. Siehe Tutorial von Oracle .Schlüssel ist df.setLenient (false); . Dies ist mehr als genug für einfache Fälle. Wenn Sie nach einer robusteren (ich bezweifle) und / oder alternativen Bibliothek wie joda-time suchen, dann schauen Sie sich die Antwort des Benutzers "tardate" an.
quelle
setLenient
oder nicht:SimpleDateFormat
Wird immer analysiert, bis das Muster übereinstimmt, und den Rest der Zeichenfolge ignorieren, sodass Sie201
als Jahr erhalten.java.util.Date
,java.util.Calendar
undjava.text.SimpleDateFormat
sind jetzt Erbe , durch die verdrängte java.time Klassen in Java gebaut 8 und höher. Siehe Tutorial von Oracle .Wie von @Maglob gezeigt, besteht der grundlegende Ansatz darin, die Konvertierung von Zeichenfolge zu Datum mithilfe von SimpleDateFormat.parse zu testen . Dadurch werden ungültige Tag / Monat-Kombinationen wie der 31.02.2008 abgefangen.
In der Praxis ist dies jedoch selten genug, da SimpleDateFormat.parse äußerst liberal ist. Es gibt zwei Verhaltensweisen, mit denen Sie sich befassen könnten:
Ungültige Zeichen in der Datumszeichenfolge Überraschenderweise wird 2008-02-2x als gültiges Datum mit dem Gebietsschema format = "JJJJ-MM-TT" übergeben. Auch wenn isLenient == false ist.
Jahre: 2, 3 oder 4 Ziffern? Möglicherweise möchten Sie auch 4-stellige Jahre erzwingen, anstatt das Standardverhalten von SimpleDateFormat zuzulassen (das "12-02-31" unterschiedlich interpretiert, je nachdem, ob Ihr Format "JJJJ-MM-TT" oder "JJJ-MM-TT" war. )
Eine strikte Lösung mit der Standardbibliothek
Ein vollständiger String-to-Date-Test könnte also so aussehen: eine Kombination aus Regex-Match und einer erzwungenen Datumskonvertierung. Der Trick mit dem regulären Ausdruck besteht darin, ihn länderspezifisch zu gestalten.
Beachten Sie, dass der reguläre Ausdruck davon ausgeht, dass die Formatzeichenfolge nur Tag-, Monats-, Jahres- und Trennzeichen enthält. Abgesehen davon kann das Format in einem beliebigen Gebietsschemaformat vorliegen: "TT / MM / JJ", "JJJJ-MM-TT" usw. Die Formatzeichenfolge für das aktuelle Gebietsschema kann folgendermaßen abgerufen werden:
Joda Time - Bessere Alternative?
Ich habe kürzlich von joda time gehört und dachte, ich würde vergleichen. Zwei Punkte:
Es ist ganz einfach zu bedienen:
quelle
Date
,SimpleDateFormat
usw.) wird jetzt von den modernen verdrängten java.time Klassen. Ebenso befindet sich das Joda-Time- Projekt im Wartungsmodus und empfiehlt die Migration zu den Klassen java.time .Sie können SimpleDateFormat verwenden
Zum Beispiel so etwas wie:
quelle
java.util.Date
,java.util.Calendar
undjava.text.SimpleDateFormat
sind jetzt Erbe , durch die verdrängte java.time Klassen in Java gebaut 8 und höher. Siehe Tutorial von Oracle .tl; dr
Verwenden Sie den strengen Modus, um a
java.time.DateTimeFormatter
zu analysierenLocalDate
. Falle für dieDateTimeParseException
.Nach dem Parsen können Sie nach einem angemessenen Wert suchen. Zum Beispiel ein Geburtsdatum innerhalb der letzten hundert Jahre.
Vermeiden Sie ältere Datums- und Zeitklassen
Vermeiden Sie die Verwendung der problematischen alten Datums- / Uhrzeitklassen, die mit den frühesten Java-Versionen geliefert werden. Jetzt ersetzt durch die java.time- Klassen.
LocalDate
&DateTimeFormatter
&ResolverStyle
Die
LocalDate
Klasse repräsentiert einen Nur-Datum-Wert ohne Tageszeit und ohne Zeitzone.Die
java.time.DateTimeFormatter
Klasse kann so eingestellt werden, dass Zeichenfolgen mit einem der drei in derResolverStyle
Aufzählung definierten Kronzeugenmodi analysiert werden . Wir fügen eine Zeile in den obigen Code ein, um jeden der Modi auszuprobieren.Die Ergebnisse:
ResolverStyle.LENIENT
ld: 2000-03-02
ResolverStyle.SMART
ld: 2000-02-29
ResolverStyle.STRICT
FEHLER: java.time.format.DateTimeParseException: Text '31 / 02/2000 'konnte nicht analysiert werden: Ungültiges Datum' 31. FEBRUAR '
Wir können sehen, dass im
ResolverStyle.LENIENT
Modus das ungültige Datum um eine entsprechende Anzahl von Tagen verschoben wird. ImResolverStyle.SMART
Modus (Standardeinstellung) wird eine logische Entscheidung getroffen, das Datum innerhalb des Monats zu halten und mit dem letztmöglichen Tag des Monats, dem 29. Februar, in einem Schaltjahr fortzufahren, da es in diesem Monat keinen 31. Tag gibt. DerResolverStyle.STRICT
Modus löst eine Ausnahme aus, die sich darüber beschwert, dass es kein solches Datum gibt.Alle drei sind je nach Geschäftsproblem und Richtlinien angemessen. Klingt so, als ob Sie in Ihrem Fall möchten, dass der strikte Modus das ungültige Datum ablehnt, anstatt es anzupassen.
Über java.time
Der java.time Rahmen in Java 8 gebaut und später. Diese Klassen verdrängen die lästigen alten Legacy - Datum-Zeit - Klassen wie
java.util.Date
,Calendar
, &SimpleDateFormat
.Weitere Informationen finden Sie im Oracle-Lernprogramm . Suchen Sie im Stapelüberlauf nach vielen Beispielen und Erklärungen. Die Spezifikation ist JSR 310 .
Das Joda-Time- Projekt, das sich jetzt im Wartungsmodus befindet , empfiehlt die Migration zu den Klassen java.time .
Sie können java.time- Objekte direkt mit Ihrer Datenbank austauschen . Verwenden Sie einen JDBC-Treiber, der mit JDBC 4.2 oder höher kompatibel ist . Keine Notwendigkeit für Strings, keine Notwendigkeit für
java.sql.*
Klassen.Woher bekomme ich die java.time-Klassen?
Das ThreeTen-Extra- Projekt erweitert java.time um zusätzliche Klassen. Dieses Projekt ist ein Testfeld für mögliche zukünftige Ergänzungen von java.time. Sie können einige nützliche Klassen hier wie finden
Interval
,YearWeek
,YearQuarter
, und mehr .quelle
java.time
Mit der in Java 8 und höher integrierten Datums- und Zeit-API ( java.time- Klassen) können Sie die
LocalDate
Klasse verwenden.quelle
ResolverStyle.SMART
der resultierende Wert an ein gültiges Datum angepasst, anstatt eine Ausnahme auszulösen. Dieser Code wird also das Ziel der Frage nicht erreichen. Siehe meine Antwort zum Beispiel und zur Lösung mitResolverStyle.STRICT
.Eine alternative strikte Lösung unter Verwendung der Standardbibliothek besteht darin, Folgendes auszuführen:
1) Erstellen Sie ein striktes SimpleDateFormat mit Ihrem Muster
2) Versuchen Sie, den vom Benutzer eingegebenen Wert mithilfe des Formatierungsobjekts zu analysieren
3) Wenn erfolgreich, formatieren Sie das aus (2) resultierende Datum mit demselben Datumsformat neu (aus (1)).
4) Vergleichen Sie das neu formatierte Datum mit dem ursprünglichen, vom Benutzer eingegebenen Wert. Wenn sie gleich sind, stimmt der eingegebene Wert genau mit Ihrem Muster überein.
Auf diese Weise müssen Sie keine komplexen regulären Ausdrücke erstellen. In meinem Fall musste ich die gesamte Mustersyntax von SimpleDateFormat unterstützen, anstatt mich auf bestimmte Typen wie Tage, Monate und Jahre zu beschränken.
quelle
Aufbauend auf Aravinds Antwort zur Behebung des Problems, auf das ceklock in seinem Kommentar hingewiesen hat , habe ich eine Methode hinzugefügt, um zu überprüfen, ob das
dateString
Zeichen kein ungültiges Zeichen enthält.So mache ich das:
quelle
Ich empfehle Ihnen,
org.apache.commons.validator.GenericValidator
Klasse von Apache zu verwenden.GenericValidator.isDate(String value, String datePattern, boolean strict);
Hinweis: streng - Gibt an, ob eine genaue Übereinstimmung mit dem Datumsmuster vorliegen soll.
quelle
Ich denke, am einfachsten ist es, eine Zeichenfolge in ein Datumsobjekt zu konvertieren und sie wieder in eine Zeichenfolge zu konvertieren. Die angegebene Datumszeichenfolge ist in Ordnung, wenn beide Zeichenfolgen noch übereinstimmen.
quelle
Angenommen, beide sind Zeichenfolgen (andernfalls wären sie bereits gültige Daten), gibt es eine Möglichkeit:
Hier ist die Ausgabe, die ich bekomme:
Wie Sie sehen können, werden beide Fälle gut behandelt.
quelle
Das funktioniert großartig für mich. Der oben von Ben vorgeschlagene Ansatz.
quelle
Es sieht so aus, als würde SimpleDateFormat das Muster auch nach setLenient (false) nicht streng überprüfen. Die Methode wird darauf angewendet, daher habe ich die folgende Methode verwendet, um zu überprüfen, ob das eingegebene Datum ein gültiges Datum ist oder nicht, wie im angegebenen Muster angegeben.
quelle
Zwei Kommentare zur Verwendung von SimpleDateFormat.
IME, das ist besser als das Instanziieren einer Instanz für jede Analyse eines Datums.
quelle
Die oben genannten Methoden zum Parsen von Datumsangaben sind nett. Ich habe gerade eine neue Überprüfung in vorhandenen Methoden hinzugefügt, die das konvertierte Datum mit dem ursprünglichen Datum mithilfe des Formatierers überprüfen. Es funktioniert also für fast jeden Fall, wie ich überprüft habe. zB 29.02.2013 ist ungültiges Datum. Bei gegebener Funktion wird das Datum gemäß den aktuell akzeptablen Datumsformaten analysiert. Es gibt true zurück, wenn das Datum nicht erfolgreich analysiert wurde.
quelle
Folgendes habe ich für die Knotenumgebung ohne externe Bibliotheken getan:
Und so geht's:
quelle
quelle
Hier würde ich das Datumsformat überprüfen:
quelle
quelle
Mit dem 'Legacy'-Datumsformat können wir das Ergebnis formatieren und mit der Quelle vergleichen.
Dieser Execerpt sagt 'false' zu source = 01.01.04 mit dem Muster '01 .01.2004 '
quelle
setLenient auf false, wenn Sie eine strikte Validierung wünschen
quelle