W3docs

Java Calendar-Klasse

Die Legacy-Klasse java.util.Calendar und GregorianCalendar — wie sie sich zu java.time verhalten.

java.util.Calendar ist die zweite Hälfte des Legacy-Datums-/Zeitpaares. Während java.util.Date lediglich ein Wrapper um einen long-Wert von Epochenmillisekunden ist, weiß Calendar, auf welches Jahr, Monat und Tag dieser Millisekunden-Wert fällt. Die Klasse wurde in Java 1.1 eingeführt, um die Kalenderarithmetik aus Date herauszulösen — deshalb sind die meisten Feldzugriffsmethoden von Date als veraltet markiert.

In modernem Code sollte man java.time bevorzugen. Aber Calendar taucht noch immer auf: in alten Code-Pfaden, in Bibliotheken, die vor Java 8 geschrieben wurden, und in JDBC-Treibern, die noch nicht aktualisiert wurden. Man muss es lesen, überbrücken und weitermachen. Diese Seite erklärt, wie man ein Calendar-Objekt erstellt, seine Felder sicher ausliest (Achtung: nullbasierte Monate), Kalenderarithmetik durchführt und — am wichtigsten — es zur modernen API überbrückt.

Calendar ist abstrakt

Calendar selbst ist eine abstrakte Klasse. Man ruft nie new Calendar(...) auf. Eine Instanz erhält man über die Factory-Methode:

Calendar cal = Calendar.getInstance();

Dies gibt eine konkrete Unterklasse zurück — fast immer GregorianCalendar — vorbelegt mit der aktuellen Zeit, der Standard-Zeitzone und dem Standard-Locale. Man kann bei Bedarf auch explizit angeben:

Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("UTC"), Locale.US);

GregorianCalendar hat auch öffentliche Konstruktoren, aber die Factory-Methode ist die Konvention.

Feldkonstanten

Calendar stellt alles über Integer-Feldkonstanten und ein generisches get(int field) bereit:

FeldBedeutungBereich
Calendar.YEARJahrvollständiges Jahr, z. B. 2026
Calendar.MONTHMonat0–11 (Januar = 0)
Calendar.DAY_OF_MONTHTag des Monats1–31
Calendar.DAY_OF_WEEKWochentag1–7 (Sonntag = 1)
Calendar.HOUR_OF_DAYStunde0–23
Calendar.MINUTEMinute0–59
Calendar.SECONDSekunde0–59
Calendar.MILLISECONDMillisekunde0–999

Zwei Fallen stecken in dieser Tabelle: MONTH ist nullbasiert (Calendar.JANUARY == 0) und DAY_OF_WEEK beginnt mit Sonntag. Off-by-one-Fehler in Legacy-Code lassen sich fast immer auf diese Punkte zurückführen.

Setzen und Arithmetik

set nimmt ein Feld und einen Wert entgegen; add führt kalendergestützte Arithmetik durch, bei der Überläufe in größere Felder übertragen werden:

Calendar cal = Calendar.getInstance();
cal.set(2026, Calendar.MAY, 29);   // Y, M, D — month is zero-based
cal.add(Calendar.DAY_OF_MONTH, 5); // → 2026-06-03

roll macht dasselbe feldweise, überträgt jedoch nicht in größere Felder — roll(DAY_OF_MONTH, 5) am 30. Mai ergibt den 4. Mai, nicht den 4. Juni. Das ist selten das Gewünschte.

Calendar-Instanzen sind veränderlich, daher bedeutet das Übergeben einer Instanz an eine Methode, dass man ein direktes Handle weitergibt. Vor der Weitergabe klonen, genauso wie bei einem Date.

Die Brücke zu java.time

Der eigentliche Grund, Calendar heute anzufassen, ist, es hinter sich zu lassen. Zwei Methoden ermöglichen das:

Instant when = cal.toInstant();
ZoneId  zone = cal.getTimeZone().toZoneId();
ZonedDateTime zdt = when.atZone(zone);

Von ZonedDateTime aus steht die gesamte moderne API zur Verfügung. In die andere Richtung:

Calendar cal = GregorianCalendar.from(zdt); // Java 8+

GregorianCalendar.from(ZonedDateTime) ist die unterstützte Konvertierung. Den Umweg über Date sollte man vermeiden.

Ausgearbeitetes Beispiel

Das folgende Beispiel zeigt die zwei Dinge, die man mit Calendar im echten Code tun wird: Felder von einer Legacy-Instanz auslesen und zur java.time-API überbrücken, um alles Nichttriviale zu erledigen.

java— editable, runs on the server

Was man dem Ergebnis entnehmen kann:

  • Calendar.MONTH für Mai gibt 4 aus. Nullbasierte Monate sind die häufigste Fehlerquelle in Legacy-Datumscode.
  • getInstance(TimeZone) bindet die Instanz an eine Zeitzone — anders als Date, das keine hat.
  • add(MONTH, 1) berücksichtigt die Monatslänge; man erhält den richtigen Tag im nächsten Monat, auch wenn Monate nicht alle 30 Tage haben.
  • cal.toInstant().atZone(cal.getTimeZone().toZoneId()) ist die einzeilige Brücke zu java.time.
  • GregorianCalendar.from(ZonedDateTime) ermöglicht es, ein Calendar-Objekt an eine alte API zurückzugeben, ohne die Zeitzone zu verlieren.

Was kommt als Nächstes

Damit schließt Teil 14 — Datum und Uhrzeit. Als Nächstes folgt Teil 15, Multithreading und Nebenläufigkeit, beginnend mit Multithreading in Java — das Modell, das jede andere API in diesem Buch geprägt hat.

Übung
Ein Calendar, der auf den 29. Mai 2026 gesetzt ist, gibt cal.get(Calendar.MONTH) zurück. Welcher Wert wird ausgegeben?
Ein Calendar, der auf den 29. Mai 2026 gesetzt ist, gibt cal.get(Calendar.MONTH) zurück. Welcher Wert wird ausgegeben?
Was this page helpful?