Zum Inhalt springen
OneKitly

Datumsarithmetik ist schwerer, als sie aussieht

Veröffentlicht am 6.6.2025 · 14 Min. Lesezeit · Alltags-Rechner

Lena Hoffmann

Lena HoffmannRedakteurin Wissenschaft & Bildung bei OneKitly

Mathematik · Physik

Anhand von 5 Quellen geprüft

Profil ansehen
Kurz gesagt

Frage, was der 31. Januar plus ein Monat ist, und keine Antwort ergibt sich zwingend aus der Mathematik. Die meisten Systeme kappen auf das Ende des kürzeren Monats und liefern den 28. Februar 2026 — oder den 29. Februar in einem Schaltjahr wie 2024. Naive Tagesarithmetik liefert etwas ganz anderes: plus 31 Tage ergibt den 3. März, plus 30 Tage den 2. März. Alle drei sind vertretbar, und genau das ist das Problem. Das Kappen hat eine Folge, die kaum jemand bemerkt: Monatsaddition ist weder umkehrbar noch assoziativ. Der 31. März minus ein Monat ist der 28. Februar, und ein Monat zurück ergibt den 28. März, nicht den 31. März. Der 31. Januar plus ein Monat plus ein Monat ist der 28. März, der 31. Januar plus zwei Monate aber der 31. März. Die Uhrzeitarithmetik bricht in eine andere Richtung. In Europe/Paris dauert der 29. März 2026 23 Stunden und der 25. Oktober 25 Stunden; 86 400 Sekunden auf einen Termin um 9:00 Uhr am 28. März addiert landen am nächsten Tag um 10:00 Uhr. Und Alter ist ein Kalendervergleich, keine Division: über alle Geburtstage von 1930 bis 2020 liefert Tage ÷ 365 in 3,49 % der Fälle das falsche Alter. Die Regel, die alles auflöst: Kalenderarithmetik in Kalenderfeldern, Zeitpunktarithmetik in UTC, und die beiden niemals vermischen.

„Einen Monat später“ hat keine eindeutige Antwort, und jede Datumsbibliothek musste sich für eine entscheiden. Monatsaddition ist weder assoziativ noch umkehrbar, ein Tag hat nicht immer 24 Stunden, und Alter ist nicht Tage geteilt durch 365,25.

Es gibt keine Arithmetik, die eine Antwort erzwingt

Eins zu einer Zahl zu addieren ist eindeutig. Einen Monat zu einem Datum zu addieren ist es nicht, denn Monate sind keine Einheit — sie sind Etiketten ungleicher Länge, von 28 bis 31 Tagen, und die Länge desjenigen, in dem du landest, hängt davon ab, in welchem du gestartet bist. Der 31. Januar plus ein Monat muss irgendwo im Februar landen, und der Februar hat keinen 31. Etwas muss nachgeben. Die nahezu universelle Wahl ist das Kappen: Monat behalten, Jahr behalten, den Tag auf den letzten gültigen zurückziehen. Das ergibt den 28. Februar 2026 und den 29. Februar 2024. Javas java.time, die ECMAScript-Temporal-API, die Intervalladdition von PostgreSQL und Pythons dateutil verhalten sich alle so — weil die Alternative schlechter ist.

Die Alternative ist, einen Monat als feste Anzahl von Tagen zu behandeln. Nimm 30, und der 31. Januar plus ein Monat wird zum 2. März 2026; nimm 31, und er wird zum 3. März. Beide überspringen den Februar vollständig — genau das, was jemand, der „einen Monat später“ verlangt, nicht will. Die Tabelle oben rechnet alle drei Definitionen gegen fünf Ausgangsdaten, und sie stimmen nur überein, wenn der Monatstag klein genug ist, um überall zu existieren. Das ist die praktische Erkenntnis: Vom 1. bis zum 28. sind alle Methoden identisch, und am 29., 30. und 31. unterscheiden sich alle irgendwo. Etwa jedes zehnte Datum liegt in der Gefahrenzone — deshalb überlebt der Fehler Tests so mühelos.

Das Kappen kostet dich Assoziativität und Umkehrbarkeit

Führ das aus und sieh zu, wie eine Eigenschaft verschwindet, die du für selbstverständlich hieltest. Der 31. März 2026 minus ein Monat kappt auf den 28. Februar. Addiere einen Monat zurück, und du erhältst den 28. März — drei Tage vor deinem Ausgangspunkt. Monatsaddition ist nicht umkehrbar: subtrahieren und dann addieren ist nicht die Identität. Derselbe Defekt zeigt sich als Verlust der Assoziativität. Der 31. Januar 2026 plus ein Monat plus ein Monat ergibt den 28. März, weil der Zwischenwert auf den 28. Februar gekappt wurde und das Kappen endgültig ist. Der 31. Januar plus zwei Monate, in einem Schritt gerechnet, ergibt den 31. März. Zwei Ausdrücke, die denselben Wert haben sollten, unterscheiden sich um drei Tage.

Das ist kein Fehler einer bestimmten Bibliothek — es ist eine Folge des Kalenders, und jede kappende Bibliothek erbt sie. Die praktische Regel, die daraus folgt, gehört auf einen Klebezettel: Baue eine Monatsreihe niemals, indem du wiederholt einen Monat auf das vorige Ergebnis addierst. Addiere immer n Monate auf das ursprüngliche Ankerdatum. Ein Abonnement, das am 31. Januar startet und iterativ verlängert wird, driftet auf den 28. und bleibt dort für immer; dasselbe Abonnement, am 31. Januar verankert und als Start + n Monate berechnet, landet auf dem 28. Februar, 31. März, 30. April, 31. Mai — genau das, was der Kunde erwartet und was der Zahlungsdienstleister abrechnet. Der Fehler ist elf Monate im Jahr unsichtbar und trifft dann auf einen Schlag ein.

Ein Tag hat keine 24 Stunden — Europe/Paris, März und Oktober 2026

Nimm die echten Regeln der tz-Datenbank statt einer Annahme. 2026 wechselt Europe/Paris am 29. März von UTC+1 auf UTC+2 und am 25. Oktober zurück. Miss den Abstand zwischen lokaler Mitternacht am 29. März und lokaler Mitternacht am 30. März: das ist 2026-03-28T23:00Z bis 2026-03-29T22:00Z, also 23 Stunden. Mach dasselbe rund um den 25. Oktober, und du erhältst 2026-10-24T22:00Z bis 2026-10-25T23:00Z, also 25 Stunden. Der Kalendertag und der 86 400-Sekunden-Tag sind verschiedene Objekte, und zweimal im Jahr fallen sie sichtbar auseinander. America/New_York macht dasselbe an anderen Daten — 23 Stunden am 8. März 2026 und 25 Stunden am 1. November.

Die Folge trifft echte Termine. Ein 9:00-Slot am 28. März 2026 in Paris ist der Zeitpunkt 2026-03-28T08:00Z. Addiere exakt 24 verstrichene Stunden, und du erhältst 2026-03-29T08:00Z, was in Paris 10:00 Uhr anzeigt — der Termin ist eine Stunde nach hinten gerutscht. Mach es im Oktober, und er rutscht eine Stunde nach vorn: 9:00 Uhr am 24. Oktober plus 24 Stunden ist 8:00 Uhr am 25. Oktober. Keines von beiden bedeutet „morgen zur selben Zeit“. „Morgen zur selben Zeit“ ist eine Kalenderoperation: Datumsfeld erhöhen, Wanduhrzeit behalten, dann den Zeitpunkt neu gegen die Zone auflösen. Eine Dauer zu addieren ist eine physikalische Operation. Sie stimmen an 363 Tagen im Jahr überein — gerade genug, damit der Fehler zufällig wirkt.

Der stille Überlauf: der 30. Februar wirft keinen Fehler

In JavaScript wirft new Date(2026, 1, 30) keine Ausnahme. Es liefert den 2. März 2026. Der Konstruktor akzeptiert jede ganze Zahl und normalisiert, indem er den Überschuss in den nächsten Monat überträgt; ein Tagesfeld von 30 in einem 28-tägigen Februar wird also stillschweigend zum 2. des Folgemonats. Dieselbe Normalisierung macht aus Monatsindex 12 den Januar des Folgejahres und aus Tag 0 den letzten Tag des Vormonats — das ist der Trick hinter der üblichen Redewendung für „Tage in diesem Monat“, new Date(y, m, 0).getDate(). Ein nützliches Verhalten, wenn du es willst, und eine stille Datenkorruption, wenn nicht — und nichts im Rückgabewert verrät dir, in welchem Fall du bist.

Deshalb heißt ein Datum zu validieren mehr, als zu prüfen, ob der Parser nicht gemeckert hat. Ein Formular, das 30.02.2026 annimmt und 2026-03-02 speichert, hat den Fehler der Nutzerin verschluckt statt gemeldet, und der Datensatz sagt jetzt etwas, das nie eingegeben wurde. Die defensive Prüfung ist eine Zeile: Datum konstruieren, dann prüfen, ob Jahr, Monat und Tag, die zurückkommen, die drei sind, die du hineingegeben hast. Sind sie es nicht, war die Eingabe kein echtes Datum. Die andere Hälfte der Verteidigung ist zu wissen, wie lang jeder Monat ist, bevor du die Eingabe überhaupt baust — 31, 28 oder 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 — und genau dafür gibt es den Tage-im-Monat-Rechner, für jedes Jahr, das du nennst.

Alter ist ein Vergleich, keine Division

Die verlockende Abkürzung ist, die verstrichenen Tage zu zählen und durch 365,25 zu teilen, mit der Begründung, das mittlere Jahr sei 365,25 Tage lang. Prüf das nach. Jemand, der am 23. August 2000 geboren wurde und am 22. August 2026 gefragt wird, hat 9 495 Tage gelebt. Teile durch 365, und du erhältst 26,0137, abgerundet 26 — die Person ist aber 25 und hat morgen Geburtstag. Teile durch 365,25, und du erhältst 25,9959, abgerundet 25, und das stimmt. Also durchlaufe den ganzen Raum statt eines Beispiels: jeder Geburtstag vom 1. Januar 1930 bis 1. Januar 2020, ausgewertet am 22. August 2026, sind 32 873 Daten. Tage ÷ 365 liefert bei 1 148 davon das falsche Alter, also 3,49 %. Tage ÷ 365,25 ist weit besser, irrt aber immer noch bei 44, also 0,13 %.

Die verbleibenden Fehler sind die grausamste Sorte: Sie treffen genau den Geburtstag. Wer am 22. August 1932 geboren wurde, hat bis zum 22. August 2026 34 333 Tage gelebt, und 34 333 ÷ 365,25 = 93,9986 — die Division sagt also 93 an dem Morgen, an dem die Person 94 wird. Kein Feinschliff am Divisor behebt das, weil kein einzelner Divisor es kann, und genau darum geht es: Der Kalender ist keine gleichmäßige Skala. Der korrekte Algorithmus enthält gar keine Division. Ziehe das Geburtsjahr vom laufenden Jahr ab und dann noch eins, wenn der laufende Monat und Tag den Geburtsmonat und -tag noch nicht erreicht haben. Drei Ganzzahlvergleiche, überall exakt, und er muss nie wissen, wie lang ein Jahr ist.

Die Regel: Kalenderfelder für Kalenderarbeit, UTC für Zeitpunkte

Fast jeder Datumsfehler ist einer von zwei Irrtümern. Entweder wurde eine Kalenderfrage mit verstrichener Zeit beantwortet — „ein Monat“ wurde zu 30 Tagen, „morgen“ zu 86 400 Sekunden, „Alter“ zu einer Division — oder eine Zeitpunktfrage wurde in lokalen Feldern beantwortet, sodass ein gespeicherter Zeitstempel wanderte, als sich der Versatz änderte. Die Abhilfe: Entscheide, bevor du eine Zeile schreibst, mit welcher Art von Größe du es zu tun hast. Verlängerungstermine, Geburtstage, Fristen, Abrechnungszeiträume und Öffnungszeiten sind Kalendergrößen: Halte sie als Jahr, Monat, Tag und Wanduhrzeit mit benannter Zone, und rechne auf diesen Feldern. Timeouts, Log-Reihenfolge, Cache-Ablauf, Ratenbegrenzung und Dauern sind Zeitpunktgrößen: Halte sie als UTC-Zeitstempel und addiere Sekunden.

Wo beide sich treffen müssen — eine Erinnerung um 9:00 Uhr Ortszeit, verschickt von einem Server, der nur Zeitpunkte kennt — konvertiere an der Grenze, und nur dort. Mach den Kalenderschritt zuerst in der benannten Zone der Nutzerin, löse das Ergebnis einmal in einen UTC-Zeitpunkt auf und gib diesen Zeitpunkt an den Scheduler. Den Versatz statt des Zonennamens zu speichern bricht in dem Moment, in dem sich die politischen Regeln ändern — und das tun sie mehrmals im Jahr; die tz-Datenbank veröffentlicht Releases genau deshalb, weil Regierungen ihre Umstellungen ständig verschieben. Und speichere einen künftigen lokalen Termin nie als bloßen UTC-Zeitpunkt: Werden die Regeln der Zone vor dem Termin geändert, entspricht der gespeicherte Zeitpunkt nicht mehr 9:00 Uhr an irgendjemandes Morgen.

Dasselbe Ausgangsdatum, drei vertretbare Definitionen von „einen Monat später“ — und die Antworten laufen auseinander
Ausgangsdatum+ 1 Monat, gekappt+ 30 Tage+ 31 Tage
31. Januar 202628. Februar 20262. März 20263. März 2026
31. Januar 2024 (Schaltjahr)29. Februar 20241. März 20242. März 2024
31. März 202630. April 202630. April 20261. Mai 2026
31. August 202630. September 202630. September 20261. Oktober 2026
30. November 202630. Dezember 202630. Dezember 202631. Dezember 2026
Tage im Monat berechnenDie Anzahl der Tage jedes Monats jedes Jahres von 1 bis 9999, die Schaltregel für den Februar Zeile für Zeile durchgerechnet, der Wochentag des 1. und des letzten Tages, wie viele von jedem Wochentag der Monat hat, und der Kalender selbst.Tool ausprobieren

Häufige Fragen

Was ist der 31. Januar plus ein Monat?
Das hängt von der Definition deines Systems ab, und keine Antwort ergibt sich zwingend aus der Mathematik. Das Kappen — das Verhalten von java.time, der Temporal-API, PostgreSQL-Intervallen und Pythons dateutil — behält Monat und Jahr und zieht den Tag auf den letzten gültigen zurück, also den 28. Februar 2026 oder den 29. Februar 2024. Festlängen-Tagesarithmetik liefert etwas anderes: plus 30 Tage ist der 2. März 2026, plus 31 Tage der 3. März. Für menschennahe Daten ist Kappen fast immer die richtige Wahl, denn wer „einen Monat später“ sagt, meint das entsprechende Datum im nächsten Monat, nicht eine feste Zahl von Tagen. Wenn du abrechnest, Verträge schließt oder planst, nenne die verwendete Regel in den Bedingungen — Kundinnen bemerken sehr wohl, wenn ein am 31. Januar begonnenes Abo am 28. Februar verlängert wird.
Warum liefert einen Monat abziehen und wieder addieren nicht das Ausgangsdatum?
Weil das Kappen Information zerstört und nichts sie zurückholen kann. Der 31. März 2026 minus ein Monat muss im Februar landen, der Februar hat keinen 31., also wird das Ergebnis auf den 28. Februar gekappt. Dieses Ergebnis weiß nicht mehr, dass es von einem 31. kam. Einen Monat auf den 28. Februar zu addieren ergibt daher den 28. März, und du bist drei Tage vor deinem Ausgangspunkt. Derselbe Mechanismus kostet dich die Assoziativität: 31. Januar plus ein Monat plus ein Monat ist der 28. März, 31. Januar plus zwei Monate in einem Schritt der 31. März. Die praktische Folge ist eine überall anwendbare Regel: Baue wiederkehrende Pläne, indem du n Monate auf das ursprüngliche Ankerdatum addierst, nie durch monatsweises Iterieren vom Vorergebnis. Iteration lässt ein einziges Kappen für immer weiterwirken.
Hat ein Tag immer 24 Stunden?
Nein, nicht als lokaler Kalendertag. In Europe/Paris dauert 2026 der 29. März 23 Stunden und der 25. Oktober 25 Stunden, weil die Zone von UTC+1 auf UTC+2 und zurück wechselt. Als Zeitpunkte gemessen ist lokale Mitternacht am 29. März 2026-03-28T23:00Z und am 30. März 2026-03-29T22:00Z — 23 Stunden Abstand. America/New_York macht dasselbe am 8. März und 1. November 2026. Manche Umstellungen sind nicht einmal volle Stunden; Lord Howe Island verschiebt um 30 Minuten. Zonen ohne Sommerzeit haben ganzjährig 24-Stunden-Tage, aber du kannst nicht annehmen, dass deine Nutzer dort sind. Die sichere Gewohnheit: „einen Tag“ im Kalendersinn als Inkrement des Datumsfelds behandeln, gegen eine benannte Zone aufgelöst, und die 86 400 Sekunden echter Zeitspannenarbeit in UTC vorbehalten.
Wie sollte ich jemandes Alter berechnen?
Mit Vergleichen, nie mit einer Division. Ziehe das Geburtsjahr vom laufenden Jahr ab, dann noch eins, wenn der laufende Monat vor dem Geburtsmonat liegt oder die Monate gleich sind und der laufende Tag vor dem Geburtstag liegt. Das ist für jedes Datum exakt. Die Divisionen scheitern messbar: über alle Geburtstage von 1930 bis 2020, ausgewertet am 22. August 2026 — 32 873 Daten — liefert verstrichene Tage ÷ 365 in 3,49 % der Fälle das falsche Alter, ÷ 365,25 in 0,13 %. Schlimmer noch: Die verbleibenden Fehler häufen sich am Geburtstag selbst, dem einen Tag, an dem Menschen nachsehen. Wer am 22. August 1932 geboren wurde, hat bis zum 22. August 2026 34 333 Tage gelebt, und 34 333 ÷ 365,25 = 93,9986 — die Division meldet also 93 am Morgen des 94. Geburtstags. Geburten am 29. Februar brauchen eine eigene Grundsatzentscheidung, denn die Rechtsordnungen sind uneins, ob der gesetzliche Geburtstag im Gemeinjahr der 28. Februar oder der 1. März ist.
Warum akzeptiert mein Formular den 30. Februar ohne Murren?
Weil die meisten Datumskonstruktoren normalisieren statt validieren. In JavaScript liefert new Date(2026, 1, 30) den 2. März 2026 ohne Fehler: Das Tagesfeld läuft über, und der Überschuss wird in den nächsten Monat übertragen. Dieselbe Regel macht aus Monatsindex 12 den Januar des Folgejahres und aus Tag 0 den letzten Tag des Vormonats — deshalb ist new Date(y, m, 0).getDate() die übliche Redewendung für die Länge eines Monats. Nichts im Rückgabewert unterscheidet einen gewollten Überlauf von einem Tippfehler. Die Abwehr ist eine Hin-und-zurück-Prüfung: Datum bauen, dann sicherstellen, dass Jahr, Monat und Tag, die du zurückliest, die drei geschriebenen sind. Weichen sie ab, weise die Eingabe zurück. Das an der Grenze zu tun ist weit billiger, als später zu entdecken, dass eine Datenbankspalte ein Datum enthält, das niemand je eingegeben hat.
Soll ich Daten in UTC oder in Ortszeit speichern?
Das hängt davon ab, was der Wert bedeutet, und „immer UTC“ zu antworten erzeugt so viele Fehler, wie es verhindert. Alles, was festhält, wann etwas geschehen ist — eine Logzeile, eine Zahlung, ein Cache-Ablauf, ein Rate-Limit-Fenster — ist ein Zeitpunkt, und Zeitpunkte gehören nach UTC. Alles, was festhält, wann etwas im Tag eines Menschen geschehen soll — eine Erinnerung um 9:00 Uhr, ein Lieferfenster, die Öffnungszeiten eines Ladens, ein wiederkehrender Termin — ist ein Kalenderwert, und ihn als nackten UTC-Zeitpunkt zu speichern ist ein Fehler, der auf eine Regeländerung wartet. Regierungen ändern Sommerzeitregeln mehrmals im Jahr, und die tz-Datenbank liefert Releases, um sie nachzuführen; ein als Zeitpunkt eingefrorener Zukunftstermin driftet von der gemeinten Wanduhrzeit weg, wenn seine Zone geändert wird. Speichere solche Werte als lokales Datum, lokale Zeit und IANA-Zonennamen und löse erst im Moment des Handelns in einen Zeitpunkt auf.

Artikel, die dich interessieren könnten

Alle Ratgeber
ErklärungSchaltjahre: die Regel, die Ausnahme und die Ausnahme von der AusnahmeDurch vier teilbar, außer Jahrhunderten, außer durch vierhundert teilbaren Jahrhunderten. Diese dreizeilige Regel existiert, weil das tropische Jahr keine 365,25 Tage hat, und ihre Arithmetik erklärt zehn gestrichene Tage im Jahr 1582 und einen Kalender, der sich exakt alle 400 Jahre wiederholt.ErklärungEinen Jahrestag ausrechnenZurückzählen und Vorwärtszählen sind zwei verschiedene Rechnungen, und am Tag selbst weichen sie um ein Jahr voneinander ab. Was dieser Rechner mit dem 29. Februar macht, was andere Datumsbibliotheken tun, und woher die traditionellen und modernen Geschenklisten tatsächlich stammen.AnleitungWie viele Wochen bis zu einem Datum? (mit Beispielen)Zähle die Wochen zwischen heute und einem künftigen Datum. Lerne die Methode „durch sieben teilen“, wann du rundest, und den Unterschied zwischen einschließender und ausschließender Zählung.AnleitungSo addierst oder subtrahierst du Tage von einem DatumZähle vorwärts zum Addieren, rückwärts zum Subtrahieren, über Monatsenden hinweg. Hier steht wie, warum Monatslängen und Schaltjahre stolpern lassen und wann Wochenenden zählen.AnleitungWie viele Tage bis zu einem Datum? (mit Beispielen)Zähle die Tage bis zu jedem künftigen Datum, verstehe inklusives und exklusives Zählen und baue einen verlässlichen Countdown.ErklärungMilitärzeit lesen und schreiben0800 ist weder „acht Uhr“ noch „08:00“ — es ist „zero eight hundred“, mit einem Zonenbuchstaben am Ende. Die vier Ziffern, die Aussprache, Mitternacht als 0000, der Streit um 2400 und der Grund, warum die 12-Stunden-Schreibweise den Mittag nicht klären kann.

Ähnliche Tools

Quellen

Hast du einen Fehler in diesem Artikel entdeckt?

Datumsarithmetik ist schwerer, als sie aussieht — OneKitly