W3docs

date_sub()

PHP erleichtert Datumsberechnungen mit DateTime::sub() und DateInterval – so ziehen Sie Zeitspannen zuverlässig von einem Datum ab.

Zeit von einem Datum in PHP subtrahieren

Eine Zeitspanne von einem Datum abzuziehen — „vor 30 Tagen", „Anfang letzten Monats", „zwei Stunden vor jetzt" — gehört zu den häufigsten Datumsaufgaben in PHP. Die alte prozedurale Funktion date_sub() (ein Alias von DateTime::sub()) wurde in PHP 8.0 entfernt, sodass moderner Code die objektorientierte Methode DateTime::sub() (oder DateTimeImmutable::sub()) zusammen mit einem DateInterval verwenden sollte.

Diese Seite erklärt, wie DateTime::sub() funktioniert, wie man den Intervall-String aufbaut, den Unterschied zwischen veränderbaren und unveränderbaren Objekten und die Kalender-Fallstricke (Monatsüberlauf, invertierte Intervalle, Sommerzeit), über die viele stolpern.

Wie DateTime::sub() funktioniert

sub() erwartet ein einzelnes DateInterval-Argument, das beschreibt, wie viel Zeit abgezogen werden soll. Die Signatur lautet:

public DateTime::sub(DateInterval $interval): DateTime

Zwei wichtige Punkte:

  • Es verändert das Objekt direkt — das ursprüngliche DateTime-Objekt wird geändert.
  • Es gibt dasselbe Objekt zurück, sodass Aufrufe verkettet werden können.
$date = new DateTime('2023-10-15', new DateTimeZone('UTC'));
$interval = new DateInterval('P5D'); // 5 days
$date->sub($interval);
echo $date->format('Y-m-d'); // Outputs: 2023-10-10

Die Angabe einer expliziten DateTimeZone macht das Ergebnis vorhersehbar; ohne sie verwendet PHP die Zeitzone aus date_default_timezone_set() oder php.ini.

Den DateInterval-String aufbauen

DateInterval verwendet das ISO-8601-Dauerformat: P[n]Y[n]M[n]DT[n]H[n]M[n]S. Das Präfix P (Period) ist obligatorisch, und ein T trennt den Datumsteil vom Zeitteil.

TokenBedeutungBeispielDauer
YJahreP3Y3 Jahre
MMonateP6M6 Monate
DTageP10D10 Tage
HStundenPT4H4 Stunden
MMinutenPT30M30 Minuten
SSekundenPT45S45 Sekunden

Beachten Sie, dass M vor dem T Monate bedeutet und nach dem T Minuten — eine häufige Fehlerquelle. Kombinieren Sie Token, um mehrere Einheiten gleichzeitig abzuziehen:

$date = new DateTime('2023-10-15 12:00:00');
$interval = new DateInterval('P2M1DT3H'); // 2 months, 1 day, 3 hours
$date->sub($interval);
echo $date->format('Y-m-d H:i:s'); // Outputs: 2023-08-14 09:00:00

Rein zeitbasierte Intervalle funktionieren genauso — hier 90 Minuten:

$date = new DateTime('2023-10-15 08:30:00');
$date->sub(new DateInterval('PT90M')); // 90 minutes
echo $date->format('Y-m-d H:i:s'); // Outputs: 2023-10-15 07:00:00

Hinweis: DateInterval prüft das Format streng. Ein ungültiger string (zum Beispiel ein fehlendes P oder PT ohne Zeittoken) wirft eine Exception. Wenn die Dauer aus Benutzereingaben stammt, schließen Sie den Konstruktor in einen try...catch-Block ein.

Veränderbar vs. unveränderbar: DateTimeImmutable bevorzugen

Da DateTime::sub() das Objekt direkt verändert, kann ein DateTime, das Sie weitergeben, unerwartet von Code geändert werden, der sub() darauf aufruft. DateTimeImmutable löst dieses Problem: Seine sub()-Methode lässt das Original unverändert und gibt eine neue Instanz zurück.

$date = new DateTimeImmutable('2023-10-15');
$earlier = $date->sub(new DateInterval('P10D'));

echo $date->format('Y-m-d');    // Outputs: 2023-10-15 (unchanged)
echo "\n";
echo $earlier->format('Y-m-d'); // Outputs: 2023-10-05

Für den größten Teil des Anwendungscodes sollten Sie standardmäßig DateTimeImmutable verwenden und das veränderbare DateTime nur dann einsetzen, wenn Sie gezielte direkte Änderungen benötigen.

Fallstricke, die Sie kennen sollten

Monatsüberlauf

Das Subtrahieren ganzer Monate begrenzt sich nicht auf den letzten Tag des Zielmonats — PHP normalisiert den Überlauf in den nächsten Monat. Das Subtrahieren eines Monats vom 31. März landet im März, nicht im Februar:

$date = new DateTime('2023-03-31');
$date->sub(new DateInterval('P1M'));
echo $date->format('Y-m-d'); // Outputs: 2023-03-03

Hier geht P1M zunächst zum „31. Februar", den PHP auf den 3. März rollt (Februar hat 2023 nur 28 Tage). Wenn Sie den letzten Tag des Vormonats benötigen, verwenden Sie stattdessen einen relativen string: new DateTime('last day of previous month').

Invertierte Intervalle addieren statt subtrahieren

Ein DateInterval hat eine invert-Eigenschaft. Ist diese 1, ist das Intervall negativ, sodass sub() die Dauer effektiv addiert:

$interval = new DateInterval('P1M');
$interval->invert = 1; // negative interval
$date = new DateTime('2023-10-15');
$date->sub($interval);
echo $date->format('Y-m-d'); // Outputs: 2023-11-15

Dies ist relevant, wenn Sie das von DateTime::diff() zurückgegebene Intervall wiederverwenden, da dieses invert automatisch je nach Richtung der Differenz setzt.

Sommerzeit

Wenn Sie Tage über eine Sommerzeitgrenze hinweg subtrahieren, passt PHP die Uhrzeit so an, dass das Kalender-Ergebnis korrekt bleibt. Wenn Sie stattdessen Stunden subtrahieren (PT24H), erhalten Sie genau 24 Stunden vergangene Zeit, was möglicherweise auf einer anderen Uhrzeit endet. Wählen Sie tages- oder stundenbasierte Intervalle bewusst danach, ob Sie „gleiche Uhrzeit, vorheriger Tag" oder „genau 24 Stunden früher" meinen.

Carbon für eine lesbare Syntax verwenden

Für große Codebasen kapselt die Carbon-Bibliothek DateTimeImmutable mit lesbaren, verkettbaren Hilfsmethoden. Sie ist optional — die nativen Klassen decken die Standardfälle ab — kann aber komplexe Logik klarer machen:

use Carbon\Carbon;

$date = Carbon::parse('2023-10-15');
$newDate = $date->subMonths(2)->subDays(5);
echo $newDate->toDateString(); // Outputs: 2023-08-10

Fazit

Verwenden Sie DateTime::sub() (oder vorzugsweise DateTimeImmutable::sub()) mit einem DateInterval, um Zeitspannen von einem Datum abzuziehen. Erstellen Sie das Intervall im ISO-8601-Format P…T…, behalten Sie den Unterschied zwischen Monaten und Minuten bei M im Hinterkopf und achten Sie auf Monatsüberlauf und invertierte Intervalle.

Weitere Informationen finden Sie unter date_add() für die umgekehrte Operation, date_diff() zum Messen der Zeitspanne zwischen zwei Daten und date_format() zum Formatieren des Ergebnisses.

Übungen

Übung
Was macht DateTime::sub() mit dem übergebenen DateInterval?
Was macht DateTime::sub() mit dem übergebenen DateInterval?
Was this page helpful?