mitmario.dev

Datum und Zeit

JavaScript Im Browser 4 Min Lesezeit 3 BeispieleLektion 1 von 6

Ein Date ist im Kern eine einzige Zahl: die Millisekunden seit dem 1. Januar 1970. Alles andere sind Wege, diese Zahl zu bauen und wieder auszugeben.

Vier Wege, eines zu bauen

Vier Wege, ein Datum zu bauen
// 1. Jetzt.
const jetzt = new Date();
console.log("Jahr:", jetzt.getFullYear());

// 2. Aus einem ISO-Text. Der zuverlässigste Weg.
const ausText = new Date("2026-08-03");
console.log("Aus Text:", ausText.toISOString());

// 3. Aus Einzelteilen. Und hier lauert die Falle:
// der Monat zählt ab null, der Tag ab eins.
const ausTeilen = new Date(2026, 7, 3);
console.log("Aus Teilen:", ausTeilen.getFullYear(), ausTeilen.getMonth(), ausTeilen.getDate());
console.log("Die 7 ist der August:", ausTeilen.toDateString());

// 4. Aus Millisekunden seit dem 1. Januar 1970.
const ausZahl = new Date(0);
console.log("Der Nullpunkt:", ausZahl.toISOString());

// Ein beliebter Trick: Tag 0 des nächsten Monats ist
// der letzte Tag des laufenden.
console.log("Letzter Tag im Februar 2024:", new Date(2024, 2, 0).getDate());
console.log("Letzter Tag im Februar 2026:", new Date(2026, 2, 0).getDate());

new Date() gibt dir den Moment, in dem die Zeile läuft.

new Date("2026-08-03") liest einen ISO-Text. Das ist der zuverlässigste Weg, und Formate wie 03.08.2026 gehören ausdrücklich nicht dazu: Was der Browser damit macht, ist nicht festgelegt.

Das kannst du in einer Zeile nachsehen. Öffne das erste Beispiel und frag in der Eingabezeile der Console nach new Date("03.08.2026").toString(). Die Antwort fängt mit Sun Mar 08 2026 an, dahinter steht noch deine Zeitzone. Aus dem 3. August ist der 8. März geworden, weil der Browser die erste Zahl für den Monat nimmt, so wie man es in den USA schreibt. Kein Fehler, keine Warnung, ein Datum fünf Monate daneben. Genau deshalb steht in einem Datum, das irgendwo gespeichert oder verschickt wird, das Jahr vorn.

new Date(2026, 7, 3) baut aus Einzelteilen. Und hier steht die Falle, um die kein Anfänger herumkommt.

new Date(0) nimmt Millisekunden.

Der Monat zählt ab null

Die Sieben in new Date(2026, 7, 3) ist der August, nicht der Juli.

Der Monat zählt ab null, der Tag ab eins, das Jahr ist das Jahr. Es gibt keinen guten Grund dafür, es ist ein Überbleibsel aus dem Jahr 1995, und es ist zu spät, daran etwas zu ändern.

Was hilft: sich einen einzigen Satz zu merken, und zwar diesen. Und getMonth() gibt dieselbe Zahl zurück, du musst also auch beim Lesen eine Eins dazurechnen, wenn ein Mensch sie sehen soll.

Eine Sache, die dadurch praktisch wird: Tag 0 eines Monats ist der letzte Tag des Monats davor. new Date(2024, 2, 0) ist der 29. Februar 2024. So bekommst du die Länge eines Monats, ohne Schaltjahre selbst zu rechnen.

Rechnen über getTime

Rechnen über getTime
const TAG = 24 * 60 * 60 * 1000;

const start = new Date("2026-08-03");
const ende = new Date("2026-08-13");

// getTime liefert Millisekunden seit 1970.
console.log("Start als Zahl:", start.getTime());

const tage = (ende.getTime() - start.getTime()) / TAG;
console.log("Tage dazwischen:", tage);

// Und so verschiebt man ein Datum.
const inZehnTagen = new Date(start.getTime() + 10 * TAG);
console.log("Zehn Tage später:", inZehnTagen.toISOString().slice(0, 10));

// Warum nicht mit den Einzelteilen? Weil Monate
// verschieden lang sind und Jahre manchmal auch.
// getUTCDate und setUTCDate, nicht getDate und setDate: ein
// ISO-Datum ohne Uhrzeit liegt auf UTC, und toISOString unten
// liest ebenfalls UTC. Wer hier mischt, ist westlich von uns
// einen Tag daneben.
const naiv = new Date("2026-08-03");
naiv.setUTCDate(naiv.getUTCDate() + 30);
console.log("30 Tage weiter ist der:", naiv.toISOString().slice(0, 10));
console.log("Ein Monat weiter wäre etwas anderes gewesen.");

Für Differenzen rechnest du mit der Zahl, nicht mit den Einzelteilen.

getTime() gibt sie dir. Ziehst du zwei voneinander ab, hast du Millisekunden, und geteilt durch die Millisekunden eines Tages hast du Tage.

Der Grund, es nicht mit getDate() und getMonth() zu versuchen: Monate sind verschieden lang, Februar manchmal auch, und die Umstellung auf Sommerzeit macht zwei Tage im Jahr 23 und 25 Stunden lang. Jede Rechnung mit Einzelteilen muss all das kennen. Die Rechnung mit Millisekunden nicht.

Ausgeben nur mit Intl

Ausgeben mit Intl
const datum = new Date("2026-08-03");

// Der Handweg. Funktioniert und macht viel Arbeit.
const selbst = `${datum.getUTCDate()}.${datum.getUTCMonth() + 1}.${datum.getUTCFullYear()}`;
console.log("Von Hand:", selbst);

// Mit Intl, wie in Lektion 8.4.
const lang = new Intl.DateTimeFormat("de-DE", {
  day: "numeric",
  month: "long",
  year: "numeric",
  timeZone: "UTC",
});

const kurz = new Intl.DateTimeFormat("de-DE", {
  day: "2-digit",
  month: "2-digit",
  year: "numeric",
  timeZone: "UTC",
});

console.log("Lang:", lang.format(datum));
console.log("Kurz:", kurz.format(datum));
console.log("Englisch:", new Intl.DateTimeFormat("en-US", { dateStyle: "long", timeZone: "UTC" }).format(datum));

// Ohne timeZone rechnet der Browser in die Zeitzone des
// Besuchers um. Westlich von hier wäre das der Vortag.
console.log("Ohne timeZone:", new Intl.DateTimeFormat("de-DE").format(datum));

Zum Anzeigen gibt es genau einen vernünftigen Weg, und das ist Intl.DateTimeFormat aus Lektion 8.4.

Du sagst die Sprache und was du sehen willst, und die Umsetzung übernimmt der Browser. Die Reihenfolge der Bestandteile, die Trennzeichen, die Monatsnamen: Alles davon ist von Sprache zu Sprache verschieden, und nichts davon willst du selbst pflegen.

Wer es doch von Hand baut, schreibt drei Zeilen, die für Deutsch stimmen, und hat dieselben drei Zeilen an neun Stellen im Projekt, sobald jemand nach einer englischen Fassung fragt.

Zeitzonen, in drei Sätzen

Ein Date kennt keine Zeitzone. Es ist ein Zeitpunkt, und die Zeitzone entsteht erst beim Ausgeben.

new Date("2026-08-03") ohne Uhrzeit wird als Mitternacht UTC gelesen. Wer das anschließend in seiner eigenen Zeitzone anzeigt, sieht westlich von Greenwich den Vortag, und genau deshalb steht in den Beispielen dieser Lektion überall timeZone: "UTC".

In welcher Zeitzone du selbst sitzt, beantwortet die Eingabezeile der Console mit Intl.DateTimeFormat().resolvedOptions().timeZone. Bei mir steht dort Europe/Berlin, und das erklärt die letzte Zeile des dritten Beispiels: Mitternacht UTC ist hier zwei Uhr morgens, also derselbe Tag. Mit und ohne timeZone steht dort deshalb beides Mal 3.8.2026, und der Unterschied, vor dem der Absatz warnt, ist von hier aus unsichtbar. Er trifft den Besucher in New York, nicht dich beim Ausprobieren.

Merksatz: Speichere Zeitpunkte immer als ISO-Text oder als Zahl, und entscheide erst beim Anzeigen, in welcher Zeitzone sie stehen sollen.

Und die ehrliche Einordnung

Alles, was über Differenzen und Formatieren hinausgeht, wird mit dieser API unangenehm. Einen Monat dazurechnen, Wochen zählen, Zeitzonen umrechnen, Wiederholungen berechnen: Dafür gibt es Bibliotheken, und dass es sie gibt, ist keine Modeerscheinung, sondern das Eingeständnis, dass Date an dieser Stelle nicht genügt.

Das ändert sich gerade. Eine neue eingebaute API namens Temporal löst genau diese Probleme und kommt nach und nach in die Browser. Wenn du in ein paar Jahren wieder mit Datumsarithmetik zu tun hast, sieh dort zuerst nach.

Zum Mitnehmen

In new Date(2026, 7, 3) ist die Sieben der August. Der Monat zählt ab null, der Tag nicht. Das ist die berühmteste Falle der ganzen Sprache.

Jetzt du

Basis Konto, kostenlos

Zu dieser Lektion gehört eine Aufgabe. Du schreibst den Code selbst, und nach jedem Lauf sagt dir eine Prüfliste, was schon stimmt.

Dafür brauchst du das Basis Konto. Es kostet nichts, und ein Passwort gibt es auch nicht.

Was in dieser Lektion steckt

  • Artikel mit 3 Beispielen zum Ausprobieren

    Steht hier, ohne Konto lesbar.

  • Aufgabe im Editor, direkt im Browser geprüft

    Öffnet sich mit dem Basis Konto.