Datumsangaben aus einem Formular sind selten so sauber, wie man es sich wünscht. Mit PHP checkdate steht eine kleine, aber zuverlässige Funktion bereit, die prüft, ob Tag, Monat und Jahr zusammen überhaupt ein existierendes Datum ergeben. Dieser Beitrag zeigt Syntax, Schaltjahr-Verhalten und den typischen Einsatz in der Formularvalidierung.
Was macht die Funktion PHP checkdate()?
Wer in PHP ein Geburtsdatum, eine Buchungsanfrage oder einen Vertragsbeginn aus einem Formular entgegennimmt, sollte sich nicht darauf verlassen, dass die Eingabe immer sauber ist. Genau hier setzt PHP checkdate an: Die Funktion prüft, ob eine Kombination aus Monat, Tag und Jahr ein gültiges Datum im gregorianischen Kalender ergibt. Sie gibt einen Boolean zurück, der sich direkt in einer if-Abfrage weiterverarbeiten lässt.

Bevor die Syntax und typische Formularszenarien folgen, lohnt sich ein kurzer Blick auf den Prüfumfang inklusive Schaltjahr-Regel.
Die Prüfung umfasst nicht nur die offensichtlichen Fälle wie "31. April" oder "Monat 13", sondern berücksichtigt auch Schaltjahre nach der gregorianischen Regel. Damit ist PHP checkdate die Standard-Antwort auf die Frage, ob "29.02.2026" überhaupt existiert. Sie funktioniert ohne externe Bibliotheken, ohne Locale-Abhängigkeit und ohne Zeitzonen-Effekte.
Syntax und Parameter im Detail
Die Signatur ist kurz, doch die Reihenfolge der Argumente ist die häufigste Stolperfalle. PHP checkdate erwartet zuerst den Monat, dann den Tag, dann das Jahr.
<?php
checkdate(int $month, int $day, int $year): bool
Wer aus dem deutschsprachigen Raum kommt, schreibt das Datum oft als Tag.Monat.Jahr und dreht die ersten beiden Argumente leicht um. Das Ergebnis wird trotzdem manchmal richtig, etwa bei checkdate(5, 5, 2026), aber bei checkdate(15, 5, 2026) fällt der Fehler erst später auf, weil 15 als Monat ungültig ist und die Funktion false liefert. Ein Test-Snippet im Code-Review klärt solche Verwechslungen früh.
<?php
var_dump(checkdate(2, 29, 2024));
/* bool(true) - 29.02.2024 ist gueltig */
var_dump(checkdate(2, 29, 2026));
/* bool(false) - kein Schaltjahr */
var_dump(checkdate(4, 31, 2026));
/* bool(false) - April hat 30 Tage */
var_dump(checkdate(13, 1, 2026));
/* bool(false) - Monat 13 existiert nicht */
Die zulässigen Bereiche sind 1 bis 12 für den Monat, 1 bis 31 für den Tag (abhängig vom Monat) und 1 bis 32767 für das Jahr. Werte außerhalb dieser Bereiche führen zu false, ebenso negative Zahlen oder die Null. Wer aus einem Formular (string)$_POST['day'] einliest, sollte vorher mit (int) casten, weil ein String wie "05" sonst als Stringtyp übergeben wird und PHP zwar konvertiert, aber bei leeren Werten unerwartete Resultate liefert.
Verhalten bei Schaltjahren und Monatsenden
Schaltjahre sind die paradigmatische Anwendung von PHP checkdate. Die gregorianische Regel lautet: Ein Jahr ist Schaltjahr, wenn es durch 4 teilbar ist, außer wenn es durch 100 teilbar ist, es sei denn, es ist auch durch 400 teilbar. Die Funktion implementiert diese Regel exakt.
<?php
$jahre = [2000, 2024, 2025, 2100, 2400];
foreach ($jahre as $jahr) {
$ist = checkdate(2, 29, $jahr);
echo "$jahr: " . ($ist ? 'Schaltjahr' : 'Kein Schaltjahr') . "\n";
}
/* 2000 Schaltjahr, 2024 Schaltjahr, 2025 nein, 2100 nein, 2400 Schaltjahr */
Ebenso werden Monatsenden zuverlässig erkannt. Der 30. Februar liefert false, der 31. April ebenfalls, der 31. Mai ist gültig. Wer ein Datum aus einer Excel-Liste importiert oder einen alten CSV-Export verarbeitet, kann mit PHP checkdate vor jeder Datenbank-Insertion eine Sicherheitsprüfung einziehen.
Anwendung in der Formularvalidierung
Der häufigste Einsatzort ist ein Formular mit drei separaten Eingabefeldern für Tag, Monat und Jahr. Die Werte werden gecastet, dann gepruft. Wer es robust mag, fügt vor checkdate noch eine Prüfung auf leere Strings ein.
<?php
$tag = (int)($_POST['tag'] ?? 0);
$monat = (int)($_POST['monat'] ?? 0);
$jahr = (int)($_POST['jahr'] ?? 0);
if (!checkdate($monat, $tag, $jahr)) {
echo 'Ungueltiges Datum, bitte korrigieren.';
} else {
/* sprintf mit Padding fuer ISO-Format */
$iso = sprintf('%04d-%02d-%02d', $jahr, $monat, $tag);
echo "Datum ist gueltig: $iso";
}
Die Kombination mit sprintf('%04d-%02d-%02d', ...) erzeugt ein normalisiertes ISO-Datum, das in eine Datenbank-Spalte vom Typ DATE oder DATETIME passt. So spart man sich das spätere Umformatieren und bekommt sofort einen sortierbaren Wert. Ergänzend kann eine Range-Prüfung verhindern, dass Geburtsdaten aus dem 19. Jahrhundert oder weit in der Zukunft akzeptiert werden.
Was checkdate() nicht prüfen kann
PHP checkdate hat klare Grenzen. Die Funktion prüft ausschließlich Tag, Monat und Jahr. Uhrzeit, Wochentag oder Format-Strings liegen außerhalb ihres Aufgabengebiets. Eine Eingabe wie "31.02.2026 14:00" muss vorher zerlegt werden, sonst kommt der Datumsteil als Komposition und die Funktion versteht nichts.
<?php
/* Falscher Versuch */
$datumString = '31.02.2026';
/* checkdate kann mit Strings nichts anfangen */
/* Korrekt: zerlegen, dann pruefen */
[$tag, $monat, $jahr] = explode('.', $datumString);
$ok = checkdate((int)$monat, (int)$tag, (int)$jahr);
var_dump($ok);
/* bool(false) - 31.02. existiert nicht */
Auch die Uhrzeit gehört nicht zum Aufgabenbereich. Wer 14:80 als Eingabe erhält und das prüfen will, ist mit DateTime::createFromFormat('H:i', $eingabe) und einer anschließenden Prüfung auf den Rückgabewert besser beraten. Die Trennung der Verantwortlichkeiten macht den Code übersichtlich: PHP checkdate für Kalenderdaten, DateTime für komplexe Datums- und Zeitstrings.
Vergleich mit DateTime::createFromFormat
Sobald ein Datum als String ankommt, ist DateTime::createFromFormat() die elegantere Variante. Sie parst und prüft in einem Schritt, akzeptiert ein explizites Format und gibt entweder ein DateTime-Objekt oder false zurück. Der Vorteil: Format und Inhalt werden gemeinsam validiert.
<?php
$eingabe = '31.02.2026';
$dt = DateTime::createFromFormat('d.m.Y', $eingabe);
$errors = DateTime::getLastErrors();
$gueltig = $dt !== false
&& ($errors === false || $errors['warning_count'] === 0);
if ($gueltig) {
echo $dt->format('Y-m-d');
} else {
echo 'Ungueltige Eingabe';
}
Der Aufruf von DateTime::getLastErrors() ist wichtig, weil createFromFormat() bei Werten wie "31.02." stillschweigend ein normalisiertes Datum erzeugen kann (z.B. 3. März). Erst mit der Errors-Prüfung wird die Validierung wirklich strikt. PHP checkdate hat hier den Vorteil, dass die Bool-Logik kompakter ist und kein Errors-Array geprüft werden muss. Beide Funktionen ergänzen sich, je nach Eingabeformat.
Praxis-Wrapper für robuste Prüfung
Im echten Projekt lohnt sich ein kleiner Wrapper, der PHP checkdate mit zusätzlichen Regeln kombiniert. Ein typisches Beispiel ist die Prüfung eines Geburtsdatums mit Mindestalter und sinnvoller Untergrenze.
<?php
function pruefeGeburtsdatum(int $tag, int $monat, int $jahr): bool
{
if (!checkdate($monat, $tag, $jahr)) {
return false;
}
$heute = (int)date('Y');
if ($jahr < 1900 || $jahr > $heute) {
return false;
}
return ($heute - $jahr) >= 18;
}
var_dump(pruefeGeburtsdatum(15, 5, 1990));
/* bool(true) */
var_dump(pruefeGeburtsdatum(31, 2, 2010));
/* bool(false) - kein 31. Februar */
var_dump(pruefeGeburtsdatum(1, 1, 2020));
/* bool(false) - noch keine 18 Jahre alt */
Solche Wrapper bauen auf der Bool-Logik von PHP checkdate auf und kapseln Geschäftsregeln, ohne die Validierung im Controller zu vermischen. Wer Unit-Tests schreibt, freut sich über die klare Schnittstelle: drei Integer rein, ein Bool raus, einfach zu mocken und zu prüfen.
flowchart TD
A[Eingabe Tag, Monat, Jahr] --> B{checkdate month, day, year}
B -->|true| C[Datum verarbeiten]
B -->|false| D[Fehlermeldung anzeigen]
C --> E[In DB speichern]
D --> F[Formular erneut zeigen]
Fazit
Die Funktion PHP checkdate ist das richtige Werkzeug, sobald Tag, Monat und Jahr getrennt vorliegen und die Gültigkeit zu prüfen ist. Sie liefert einen Boolean, berücksichtigt Schaltjahre korrekt und ist unabhängig von Locale, Zeitzone und Format. Wer Datumsangaben aus Strings parsen muss, kombiniert PHP checkdate mit DateTime::createFromFormat() oder explode-Logik und gewinnt damit eine zuverlässige Validierungs-Pipeline. Die Funktion bleibt nach 20 Jahren PHP-Geschichte einer der am wenigsten überraschenden Helfer und gehört in jedes Formular, das Datumsfelder akzeptiert.