PHP-Skript: Datumsdifferenz in Jahren, Monaten und Tagen
Dieses Tutorial zeigt, wie man mit PHP den Abstand zweier Datumsangaben berechnet, die als UNIX-Zeitstempel vorliegen. Während die Berechnung auf Basis einer einzigen Einheit (z.B. die Anzahl der Tage) sehr einfach, aber für uns als Menschen häufig sehr wenig anschaulich ist, gestaltet sich die gemischte Angabe in Jahren, Monaten und Tagen etwas schwieriger.
Anwendungsbeispiel
Es sind mittlerweile 35 Jahre, 0 Monate und 14 Tage seit dem Fall der Berliner Mauer vergangen.
Wir müssen uns noch 1 Jahre, 0 Monate und 12 Tage gedulden, bis die Raumsonde BepiColombo in die Umlaufbahn des Merkur einschwenkt.
Syntax
string datediff_ymd (int $pDate1, int $pDate2, string $pTemplate)
$pDate1
Erste Datumsangabe als UNIX-Zeitstempel.
$pDate2
(optional) Zweite Datumsangabe als UNIX-Zeitstempel. Wenn nichts oder 0 angegeben wird, wird das aktuelle
Datum verwendet.
$pTemplate
(optional) Ein Template-String für die Ausgabe. Dabei wird %d mit der Anzahl der Tage, %m mit der Anzahl der
Monate und %y mit der Anzahl der Jahre ersetzt. Wird nichts angegeben, so wird die Vorlage "%y Jahre, %m Monate
und %d Tage" verwendet.
Voraussetzungen
Die beiden Datumsangaben liegen in den Variablen $pDate1 und $pDate2 als Ganzzahl in Form eines UNIX-Zeitstempels vor. Solch einen UNIX-Zeitstempel liefert zum Beispiel die time()-Funktion für das aktuelle Datum zurück, kann aber ebenso mit der mktime()-Funktion von einem beliebigen Datum erstellt werden. Beispiel:
$lDate1 = time();
$lDate2 = mktime(12, 0, 0, 7, 14, 2015);
Kommentiertes Skript
Zu allererst stellen wir sicher, dass das zweite übergebene Datum auch das größere der beiden ist; das erspart uns später einigen Ärger mit negativen Werten. Für den Fall, dass doch das erste Datum das größere ist, tauschen wir den Inhalt der Variablen $pDate1 und $pDate2 miteinander. Dafür verwendet man üblicherweise den Dreieckstausch. Da die beiden Daten jedoch als Ganzzahlen vorliegen, können wir hier einen optimierten Tausch auf Basis einiger binärer XOR-Operationen durchführen (zur Erklärung siehe weiterführende Links).
if ($pDate1 > $pDate2) {
$pDate1 ^= $pDate2 ^= $pDate1 ^= $pDate2;
}
Nun bestimmen wir mit Hilfe der date()-Funktion die einzelnen Bestandteile der beiden Datumsangaben.
$lDay1 = date('d', $pDate1);
$lMonth1 = date('m', $pDate1);
$lYear1 = date('Y', $pDate1);
$lDay2 = date('d', $pDate2);
$lMonth2 = date('m', $pDate2);
$lYear2 = date('Y', $pDate2);
Nachdem wir diese Vorarbeit geleistet haben, machen wir uns daran die Differenz der Datumsangaben zu berechnen. Das ganze funktioniert im Prinzip wie eine schriftliche Subtraktion, bei der die Tage die kleinste Stelle, die Jahre die größte Stelle bilden:
Ist die obere Zahl größer als die untere, können wir problemlos subtrahieren. Ist es andersherum, würden wir dagegen einen negativen Wert erhalten. Wir leihen uns daher schon etwas von der nächsten Stelle, indem wir einen Übertrag machen. Da in unserem Dezimalsystem jede Stelle den zehnfachen Wert der vorherigen hat, erhalten wir so generell 10 dazu. Bei Datumsangaben gestaltet sich das ungleich schwerer, wie wir gleich sehen werden.
Beginnen wir also mit der Differenz der Tage. Erhalten wir dabei einen negativen Wert, so setzen wir einen Übertrag in der Variable $lCarry und leihen uns damit den Wert eines Monats. Das Problem: ein Monat kann 31 oder 30 Tage umfassen, der Februar zudem 28, in Schaltjahren 29. Wir müssen daher herausbekommen, wie viel Tage der Monat hat, in dem das kleinere Datum liegt, damit wir überhaupt wissen, welchen Zugewinn wir durch das Leihen eines Monats erhalten. Glücklicherweise bietet uns die date()-Funktion mit dem Parameter t eine einfache Möglichkeit die Anzahl der Tage eines Monats zu bestimmen, die sogar Schaltjahre korrekt berücksichtigt.
$lDays = $lDay2 - $lDay1;
if ($lDays < 0) {
$lDays += date('t', $pDate1);
$lCarry = 1;
} else {
$lCarry = 0;
}
Weiter geht es mit den Monaten. Hier müssen wir nun auch den Übertrag der vorherigen Rechnung berücksichtigen. Gegebenenfalls müssen wir uns ebenfalls bei den Monaten ein Jahr leihen. Glücklicherweise hat jedes Jahr 12 Monate, sodass sich der Übertrag hier einfach gestaltet.
$lMonths = $lMonth2 - $lMonth1 - $lCarry;
if ($lMonths < 0) {
$lMonths += 12;
$lCarry = 1;
} else {
$lCarry = 0;
}
Und zum Abschluss noch die Jahre. Hier können sich keine negativen Werte mehr ergeben, da wir oben ja bereits sichergestellt hatten, dass das zweite Datum stets größer als das erste Datum ist.
$lYears = $lYear2 - $lYear1 - $lCarry;
Das Ergebnis der ganzen Rechnerei wird nun auf Basis des Template-Strings aus der Variablen $pTemplate zurückgegeben. Das Ersetzen der Template-Variablen übernimmt die str_replace()-Funktion.
return str_replace(array('%y', '%m', '%d'),
array($lYears, $lMonths, $lDays), $pTemplate);
Skript zum Herunterladen
Das Skript ist in einer Textdatei mit der Kodierung UTF-8 hinterlegt, damit es nicht vom PHP-Interpreter auf meinem Webspace ausgeführt wird und Sie es herunterladen können. Sie können den benötigten Programmcode entweder in Ihr Skript hinüberkopieren oder aber das Skript speichern und die Endung auf .php ändern.
datumsdifferenz-in-jahren-monaten-und-tagen.txt
Weiterführende Links
- Swap Variable’s Values in PHP (Bukisa.com)
- How to swap two variables without using third variable? (AllInterview.com)