Wie lässt sich eine Datumsangabe auf Korrektheit prüfen?
Die Überprüfung einer Datumsangabe muss prinzipiell auf zweierlei Weisen erfolgen:
- Die syntaktische Struktur des zu prüfenden Datum-Strings muss den formalen Vorgaben eines validierbaren Formatierungs-Musters (Pattern) entsprechen. Z.B. 2023-03-14, 20230314 oder 14.03.2013
- Die Angabe muss kalendarisch korrekt sein. Z.B. Ausschluss des 29. Februar außerhalb von Schaltjahren, des 31. April, etc.
Wird eine vorgegebene Syntax in der Form JJJJ-MM-TT
eingehalten, so beschränkt sich die
Überprüfung auf die zweite Bedingung.
Die
statische Methode LocalDate.parse()
nimmt
den Datum-String in der angegebenen Form entgegen und
übersetzt ihn bei kalendarischer Korrektheit intern
mittels DateTimeFormatter.ISO_LOCAL_DATE
in
ein LocalDate
-Objekt. Wenn das Datum
kalendarisch ungültig ist oder der String in einem
anderen Format vorliegt, wird eine DateTimeParseException
geworfen.
import java.time.LocalDate; import java.time.format.DateTimeParseException; public class DatumPruefen { public static void main(String[] args) { String[] datum = { "2023-03-16", "2023-4-13", "2023-02-29", "2003-13-17", "2003.12.31" }; for (int i = 0; i < datum.length; i++) { if (!isDateValid(datum[i])) { System.out.println("Datum nicht valide"); } else { System.out.println("Datum valide"); } System.out.println(); } } public static boolean isDateValid(String date) { try { System.out.println(date); System.out.println(LocalDate.parse(date)); } catch (DateTimeParseException e) { return false; } return true; } } // Ausgabe // 2023-03-16 // 2023-03-16 // Datum valide // 2023-4-13 // Datum nicht valide // 2023-02-29 // Datum nicht valide // 2003-13-17 // Datum nicht valide // 2003.12.31 // Datum nicht valide
Das erste Beispiel zeigt dies anhand eines Arrays mit
einem gültigen und vier, aus unterschiedlichen
Gründen ungültigen Datum-Strings.
Die
Methode isDateValid(String date)
wird
innerhalb einer Schleife wiederholt jeweils mit einem im
Array gespeicherten String als Parameter aufgerufen
[10]. Der Übersichtlichkeit halber wird er
innerhalb der Methode zunächst ausgegeben.
Anschließend wird versucht, den String durch die
o.a. Methode LocalDate.parse()
in ein LocalDate
-Objekt
zu wandeln. Wird das Parsen erfolgreich durchlaufen,
gibt die Methode true
zurück, im
anderen Fall false
. Man erkennt, dass die
Übersetzung des Datum-Strings bei unzulässiger
Syntax [35, 44] und falschen kalendarischen Angaben [38,
41] nicht erfolgreich verläuft.
Abweichend formatierte Datum-Strings
Liegt ein Datum-String nicht in der Standardsyntax vor,
muss zu dessen Übersetzung ein DateTimeFormatter
hinzugezogen werden. Die Klasse ermöglicht die
weitgehend freie Formatierung eines Datum-Strings nebst
dessen Validierung. Ein Muster (Pattern)
definiert hierbei durch Art, Anzahl und Anordnung
alphanumerischer Zeichen die syntaktische Form der
Datumsangabe1.
Mit diesem als Argument wird durch die statische Methode
DateTimeFormatter.ofPattern()
ein DateTimeFormatter
-Objekt
erzeugt. Die Methode ist zweifach überladen und
kann neben einem ersten Parameter in Form des
Pattern-Strings, als zweiten noch eine Gebietsvariable,
eine statische Locale
-Konstante, erhalten.
Die Methode ofPattern()
übersetzt das
angegebenen Pattern in die zugehörigen
Datums-Bestandteile, die Felder und gibt bei
Fehlerfreiheit ein neues DateTimeFormatter
-Objekt
zurück.
Dieser Formatter kann durch withResolverStyle()
weiter spezifiziert werden. Die Methode wertet dabei die
gebildeten Datum-Felder aus und interpretiert diese in
Abhängigkeit von einer Konstanten des Enum ResolverStyle
.
Sie steuert die Art des Umgangs mit den Datumswerten in
Abhängigkeit vom jeweiligen Datumsfeld.
-
ResolverStyle.STRICT
- Strenge Auslegung der Datumsangabe nach ISO-Maßgabe. Akzeptiert z.B. einen 29. Februar nur in Schaltjahren [47].
-
ResolverStyle.SMART
- 'Intelligente' Auslegung der Datumsangabe, die in ihren Auswirkungen zwischen den verschiedenen Feldern unterscheidet. Begrenzt z.B. einen Überlauf des Tages im Monat auf den letzten zulässigen Monatstag [46].
-
ResolverStyle.LENIENT
- Unterscheidet ebenfalls zwischen den einzelnen Feldern und verrechnet überlaufende Werte mit den übergeordneten Nachbarfeldern [45, 50].
import java.time.LocalDate; import java.time.format.DateTimeFormatter; import java.time.format.DateTimeParseException; import java.time.format.ResolverStyle; public class DatumPruefen { public static void main(String[] args) { String[] datum = { "29.02.2020", "29.02.2023", "34.13.2000", "29.2.1933", "07.01.0193" }; ResolverStyle[] styles = { ResolverStyle.LENIENT, ResolverStyle.SMART, ResolverStyle.STRICT }; for (int i = 0; i < datum.length; i++) { System.out.println(datum[i]); for (int j = 0; j < styles.length; j++) { if (!isDateValid(datum[i], styles[j])) { System.out.println("\tDatum nicht valide"); } else { System.out.println("\tDatum valide"); } } System.out.println("-----------------"); } } public static boolean isDateValid(String date, ResolverStyle style) { DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern("dd.MM.uuuu"); DateTimeFormatter formatter = dateFormatter.withResolverStyle(style); System.out.print(style.toString() + ": "); try { System.out.print(LocalDate.parse(date, formatter)); } catch (DateTimeParseException e) { return false; } return true; } } // Ausgabe // 29.02.2020 // LENIENT: 2020-02-29 Datum valide // SMART: 2020-02-29 Datum valide // STRICT: 2020-02-29 Datum valide // ----------------- // 29.02.2023 // LENIENT: 2023-03-01 Datum valide // SMART: 2023-02-28 Datum valide // STRICT: Datum nicht valide // ----------------- // 34.13.2000 // LENIENT: 2001-02-03 Datum valide // SMART: Datum nicht valide // STRICT: Datum nicht valide // ----------------- // 29.2.1933 // LENIENT: Datum nicht valide // SMART: Datum nicht valide // STRICT: Datum nicht valide // ----------------- // 07.01.0193 // LENIENT: 0193-01-07 Datum valide // SMART: 0193-01-07 Datum valide // STRICT: 0193-01-07 Datum valide // -----------------
Im Beispiel werden zwei Arrays gebildet. Das erste
enthält einige Datum-Strings, das zweite die
erwähnten drei Konstanten des Enum ResolverStyle
.
Beide Arrays werden in geschachtelten Schleifen
durchlaufen und die Datumswerte und Konstanten als
Parameter an die Methode isDateValid()
übergeben.
In dieser werden dann für jedes
Datum-Konstanten-Paar die o.a. Prozesse ausgeführt:
Der Datum-String wird gemäß des angegebenen
Patterns übersetzt [26], das resultierende
Formatter-Objekt mit der übergebenen Konstante
weiterverarbeitet [27] und auf dieser Basis das Datum
letztendlich geparsed und ausgegeben [30]. Je nach
Erfolg des abschließenden Parsens gibt die Methode
true
oder false
zurück.
1) Die Variationsmöglichkeiten der
Pattern-Angaben sind sehr vielfältig und
können in den Java-Docs der Klasse DateTimeFormatter
nachgeschlagen werden.
Wenn Ihnen javabeginners.de gefällt, freue ich mich über eine Spende an diese gemeinnützigen Organisationen.