🚀The world's best VBA AI has evolved. ExcelMaster is now an autonomous Agent.Read more →
Back to Blog

VBA DateAdd & DateDiff in Excel — Datumsrechnung ohne den Monatslängen-Bug

|

VBA DateAdd & DateDiff in Excel — Datumsrechnung ohne den Monatslängen-Bug

TL;DR — Ein Datum ist ein Double, also ist myDate + 1 morgen und myDate - 7 letzte Woche — schlichte Arithmetik stimmt für Tage. Sie fällt bei Monaten und Jahren auseinander, weil ein Monat keine 30 Tage und ein Jahr keine 365 Tage hat. DateAdd("m", 1, d) kennt den Kalender; DateDiff("d", a, b) zählt ganze Tage; und DateDiff("yyyy", a, b) zählt überschrittene Jahresgrenzen, nicht verstrichene Zeit — weshalb 31. Dez → 1. Jan „1 Jahr" ergibt.

Sub DateMathDemo()
    Debug.Print #2026-01-31# + 1                       ' 2026-02-01  - Tage: schlichtes + geht
    Debug.Print DateAdd("m", 1, #2026-01-31#)          ' 2026-02-28  - monatsbewusst, begrenzt
    Debug.Print DateDiff("d", #2026-01-01#, #2026-03-01#) ' 59       - ganze Tage dazwischen
    Debug.Print DateSerial(2026, 3, 0)                 ' 2026-02-28  - letzter Tag im Februar
End Sub

Datumsrechnung in VBA steht und fällt mit einer Tatsache: Ein Datum ist ein Double, das Tage zählt. Das macht Tages-Mathematik trivial — + 1, - 7, Date + 30 funktionieren alle einfach, weil ein Tag genau 1 ist. Der Ärger beginnt, wenn Sie annehmen, derselbe Trick skaliere auf Monate und Jahre, die keine feste Länge haben. DateAdd, DateDiff und DateSerial gibt es genau dafür: den kalenderbewussten Teil zu erledigen, den schlichtes + und - nicht können.

Was Sie lernen

  • Das mentale Modell — schlichtes +/- stimmt für Tage, ist falsch für Monate und Jahre
  • DateAdd(interval, number, date) und die Intervallcodes, die beißen ("m" vs. "n", "y" vs. "yyyy")
  • Warum DateAdd("m", 1, 31. Jan) den 28. Feb ergibt — Monatsende-Intelligenz, die Sie mit + nicht bekommen
  • DateDiff zählt überschrittene Grenzen, nicht verstrichene Dauer — das „1 Jahr" aus einem einzigen Tag
  • DateSerial baut ein Datum aus Teilen ohne Locale-Mehrdeutigkeit, und die Letzter-Tag-des-Monats-Redewendung
  • Wann Sie schlichte Arithmetik nehmen und wann eine Funktion Pflicht ist

Das mentale Modell: Schlichte Mathematik reicht nur für Tage

Weil ein Datum ein Double aus Tagen ist, braucht Tages-Arithmetik überhaupt keine Funktion:

tomorrow = Date + 1
lastWeek = Date - 7
Debug.Print #2026-02-28# + 1        ' 2026-03-01 - VBA rollt den Monat fuer Sie um

Das ist wirklich korrekt — VBA meistert Monatsenden und Schaltjahre, wenn Sie ganze Tage addieren, weil es bloß zur Seriennummer hinzuaddiert. Der Fehler ist, einen Monat oder ein Jahr für eine Anzahl Tage zu halten:

nextMonth = Date + 30      ' FALSCH - 30 Tage sind kein Monat
nextYear  = Date + 365     ' FALSCH - verpasst den Schalttag, driftet jedes Jahr

+ 30 landet je nach Monat auf verschiedenen Tagen; + 365 liegt in jeder Spanne, die den 29. Februar enthält, um einen Tag daneben. In dem Augenblick, in dem Ihre Einheit Monat oder Jahr ist, ist schlichte Arithmetik ein Bug, und Sie brauchen DateAdd.

DateAdd und die Intervallcodes, die beißen

DateAdd(interval, number, date) addiert number Einheiten von interval zu date. Der interval ist ein String-Code, und zwei Kollisionen verursachen den Großteil der Verwirrung:

Code Einheit Vorsicht
"yyyy" Jahr "y" ist nicht Jahr — es bedeutet Tag des Jahres
"q" Quartal
"m" Monat "m" ist Monat; Minute ist "n"
"ww" Woche
"d" Tag "y" und "w" verhalten sich auch als Tage
"h" Stunde
"n" Minute nicht "m"
"s" Sekunde
DateAdd("m", 15, startTime)   ' addiert 15 MONATE - vermutlich nicht gemeint
DateAdd("n", 15, startTime)   ' addiert 15 MINUTEN - das n, das Sie eigentlich wollten

Die Verwechslung "m" / "n" ist der Paradebug: Greifen Sie zu "m" in dem Glauben, es hieße „Minute", und Sie haben klammheimlich fünfzehn Monate zu einem Zeitstempel addiert. Sprechen Sie die Codes einmal laut aus — m ist Monat, n ist Minute, yyyy ist Jahr — und die ganze Familie hört auf, fehleranfällig zu sein. number darf negativ sein, um zu subtrahieren, und das Ergebnis ist immer ein richtiges Datum.

Warum DateAdd den 28. Feb ergibt, wenn Sie zum 31. Jan einen Monat addieren

Das ist der Gewinn, den schlichte Arithmetik Ihnen nie geben kann. Addieren Sie einen Monat zum 31. Januar, gibt es keinen „31. Februar" zum Landen, also begrenzt DateAdd auf den letzten gültigen Tag des Zielmonats:

DateAdd("m", 1, #2026-01-31#)   ' 2026-02-28  (2028 ergaebe 2028-02-29)
DateAdd("m", 1, #2026-03-31#)   ' 2026-04-30  (April hat 30 Tage)
DateAdd("yyyy", 1, #2028-02-29#) ' 2029-02-28 (kein Schalttag naechstes Jahr)

DateAdd weiß, wie viele Tage jeder Monat hat, und passt Schaltjahre automatisch an — genau das Wissen, das + 30 wegwirft. Wenn Sie Fälligkeitsdaten, Verlängerungen oder „denselben Tag im nächsten Monat" berechnen, ist dieses Begrenzen das gewünschte Verhalten und der Grund, Monatsrechnung nie von Hand zu stricken.

DateDiff zählt überschrittene Grenzen, nicht verstrichene Zeit

DateDiff(interval, date1, date2) sieht aus wie „wie viel Zeit zwischen zwei Datumswerten", und für "d" (Tage) ist es das auch. Für "m", "yyyy", "q" und "ww" bedeutet es etwas Subtileres und Überraschenderes: wie viele Intervallgrenzen zwischen den beiden Datumswerten liegen, nicht wie viel Zeit tatsächlich verstrich.

DateDiff("yyyy", #2025-12-31#, #2026-01-01#)  ' 1  - eine Neujahrsgrenze, aber EINEN Tag entfernt
DateDiff("m",    #2026-01-31#, #2026-02-01#)  ' 1  - eine Monatsgrenze, einen Tag entfernt
DateDiff("d",    #2026-01-31#, #2026-02-01#)  ' 1  - ein echter Tag (dieser ist woertlich)

DateDiff("yyyy", …) ist also eine Zählung der Kalenderjahr-Wechsel, was nicht jemandes Alter und nicht verstrichene Jahre ist. Für eine echte verstrichene Zählung berechnen Sie die Grenzdifferenz und korrigieren dann — beim Alter ziehen Sie 1 ab, wenn der Geburtstag dieses Jahr noch nicht war:

age = DateDiff("yyyy", dob, Date)
If DateSerial(Year(Date), Month(dob), Day(dob)) > Date Then age = age - 1

DateDiff liefert außerdem eine negative Zahl, wenn date1 später als date2 ist — ein praktischer Weg, die Reihenfolge zu testen. Die Regel: Nehmen Sie "d" bedenkenlos für ganze Tage; behandeln Sie "m"/"yyyy"/"q" als Grenzzählungen und korrigieren Sie, bevor Sie das Ergebnis eine Dauer nennen.

DateSerial baut ein Datum aus Teilen, ohne Locale-Mehrdeutigkeit

Wenn Sie Jahr, Monat und Tag als getrennte Zahlen haben, kleben Sie sie nicht in eine Zeichenkette und hoffen, dass CDate sie in der richtigen Reihenfolge liest — das hängt von den Regionseinstellungen des Rechners ab und vertauscht über Grenzen hinweg klammheimlich Tag und Monat. DateSerial(year, month, day) baut das Datum direkt, ohne Text und ohne Mehrdeutigkeit:

d = DateSerial(2026, 2, 1)     ' immer der 1. Februar 2026, auf jeder Maschine

Noch besser: DateSerial normalisiert Überlauf — Monat 13 rollt ins nächste Jahr, Tag 0 ist der letzte Tag des Vormonats. Das liefert die zwei nützlichsten Redewendungen im Datumscode:

lastDayOfMonth = DateSerial(y, m + 1, 0)   ' Tag 0 = letzter Tag im Monat m
firstOfNextQ   = DateSerial(y, m + 3, 1)   ' drei Monate weiter, Tag 1

DateSerial(y, m + 1, 0) ist das kanonische „letzter Tag dieses Monats" — keine Nachschlagetabelle mit Monatslängen, kein Schaltjahr-Sonderfall. Kombinieren Sie es mit Year, Month und Day aus der Anleitung zur Teil-Extraktion, und Sie können jedes Datum relativ zu einem anderen bauen.

Das ehrliche Fazit: Tage von Hand, alles andere per Funktion

Die Trennlinie ist klar, und auf der richtigen Seite zu bleiben beseitigt fast jeden Datumsrechnungs-Bug:

  • Tage → schlichte Arithmetikdate + n, date - n. Korrekt und schnell; VBA rollt Monate und Schaltjahre für Sie.
  • Monate / Jahre → DateAdd → nie + 30 oder + 365. DateAdd("m", …) begrenzt auf echte Monatslängen; denken Sie daran, "m" ist Monat und "n" ist Minute.
  • Abstände → DateDiff, aber lesen Sie es als Grenzen"d" sind wörtliche Tage; "m"/"yyyy" zählen Grenzüberschreitungen, also korrigieren Sie, bevor Sie es eine Dauer nennen.
  • Aus Teilen bauen → DateSerial → keine Locale-Mehrdeutigkeit, und DateSerial(y, m + 1, 0) ist die Letzter-Tag-des-Monats-Redewendung.

Der eine Satz zum Behalten: Der +-Operator kennt den Kalender nicht, und DateDiff misst keine Zeit. Nehmen Sie jedes für die eine Sache, in der es recht hat.

Wie ExcelMaster hilft

Die teuren Datumsrechnungs-Bugs sind die plausiblen: ein Verlängerungsdatum, als + 30 berechnet, das über die Monatslängen driftet, ein „Alter" aus DateDiff("yyyy", …), das rund um Geburtstage ein Jahr danebenliegt, ein Fälligkeitsdatum, aus einer Zeichenkette gebaut, das bei den Regionseinstellungen eines Kollegen Tag und Monat vertauscht. Jeder sieht in einem schnellen Test richtig aus und scheitert an den Randfällen.

ExcelMaster schreibt die kalenderkorrekte Fassung. Beschreiben Sie die Berechnung — „erster Werktag des nächsten Monats", „Rechnung fällig in 45 Tagen", „Monate zwischen zwei Datumswerten" — und es wählt schlichte Arithmetik für Tage, DateAdd mit dem richtigen Intervallcode für Monate und Jahre und DateSerial, um ohne regionale Mehrdeutigkeit aus Teilen zu bauen, und rechnet DateDiff-Grenzzählungen in echte Zeiträume um. Sie beschreiben das Datum, das Sie brauchen; es schreibt die Rechnung, die Monatsenden und Schaltjahre übersteht.

Häufig gestellte Fragen

Wie addiere ich in VBA Tage zu einem Datum?

Nehmen Sie einfach Arithmetik: Ein Datum ist eine Anzahl Tage, also addiert newDate = myDate + 7 eine Woche, und myDate - 1 ist gestern. VBA rollt Monatsenden und Schaltjahre für Sie, wenn Sie ganze Tage addieren. Greifen Sie nur dann zu DateAdd, wenn die Einheit ein Monat oder ein Jahr ist, denn die haben keine feste Anzahl Tage.

Was ist der Unterschied zwischen DateAdd und dem bloßen + in VBA?

Schlichtes + addiert Tage und ist für Tagesrechnung korrekt. DateAdd(interval, number, date) versteht den Kalender, also addiert DateAdd("m", 1, …) einen echten Monat — aus 31. Jan wird 28. Feb, kein unmöglicher 31. — und DateAdd("yyyy", 1, …) meistert Schaltjahre. Nehmen Sie + für Tage; nehmen Sie DateAdd für Monate und Jahre, wo + 30 oder + 365 driften würde.

Warum liefert DateDiff in VBA die falsche Anzahl Jahre?

Weil DateDiff("yyyy", …) überschrittene Jahresgrenzen zählt, nicht verstrichene Jahre. Vom 31. Dezember zum 1. Januar liefert es 1, obwohl nur ein Tag verging. Für ein Alter oder echte verstrichene Jahre berechnen Sie DateDiff("yyyy", dob, Date) und ziehen 1 ab, wenn der diesjährige Geburtstag noch nicht war. Nehmen Sie "d", wenn Sie eine wörtliche Zählung der Tage wollen.

Was bedeuten die Intervallcodes in DateAdd?

Es sind String-Codes für die Einheit: "yyyy" Jahr, "q" Quartal, "m" Monat, "ww" Woche, "d" Tag, "h" Stunde, "n" Minute, "s" Sekunde. Die zwei Fallen sind, dass Minute "n" ist, nicht "m" (das ist Monat) und dass "y" den Tag des Jahres meint, nicht das Jahr (Jahr ist "yyyy"). Dieselben Codes gelten in DateDiff und DatePart.

Wie bekomme ich in VBA den letzten Tag des Monats?

Nehmen Sie DateSerial mit Tag 0 des nächsten Monats: DateSerial(Year(d), Month(d) + 1, 0). Tag 0 ist als der letzte Tag des Vormonats definiert, also liefert das den letzten Tag von ds Monat, ohne Monatslängen-Tabelle und ohne Schaltjahr-Sonderfall. DateSerial baut Datumswerte auch aus Teilen, ohne die regionale Tag/Monat-Mehrdeutigkeit des Zeichenketten-Parsens.

Getestet in

Getestet in: Excel 365 (Windows 11), VBA 7.1 — zuletzt geprüft am 26.08.2026.

Verwandte Anleitungen: VBA Now, Date & Time · VBA Weekday & DatePart · VBA CStr, CDate & Val · VBA Format · VBA For Loop