W3docs

Java TemporalAdjusters

Datumsberechnungen in Java mit TemporalAdjusters – firstDayOfMonth, next, previous und eigene Adjuster.

plusDays(7) fügt sieben Tage hinzu. withDayOfMonth(15) springt auf den 15. Diese beiden Varianten decken die einfachen Fälle ab. Ein TemporalAdjuster ist ein funktionsartiges Objekt, das Sie an Temporal.with(adjuster) übergeben, um Fälle zu behandeln, in denen das neue Datum vom aktuellen auf kompliziertere Weise abhängt: „der erste Montag des nächsten Monats", „der letzte Tag dieses Quartals", „das amerikanische Thanksgiving des nächsten Jahres".

Das Interface hat eine einzige Methode:

@FunctionalInterface
interface TemporalAdjuster {
  Temporal adjustInto(Temporal temporal);
}

Normalerweise implementieren Sie diese nicht selbst. Die Klasse java.time.temporal.TemporalAdjusters (beachten Sie das sAdjusters, Plural) enthält etwa ein Dutzend eingebauter Adjuster für die gängigsten Fälle, und mit LocalDate.with(adjuster) wenden Sie diese an.

Der eingebaute Katalog

Importieren Sie statisch; der Code liest sich so besser:

import static java.time.temporal.TemporalAdjusters.*;

Dann:

AdjusterWirkung
firstDayOfMonth()Tag → erster Tag desselben Monats
lastDayOfMonth()Tag → letzter Tag desselben Monats
firstDayOfNextMonth()Tag → erster Tag des nächsten Monats
firstDayOfYear()Tag → 1. Januar desselben Jahres
lastDayOfYear()Tag → 31. Dezember desselben Jahres
firstDayOfNextYear()Tag → 1. Januar des nächsten Jahres
next(DayOfWeek dow)der nächste dow strikt nach dem Datum
nextOrSame(DayOfWeek dow)heute, wenn es dow ist, sonst nächster dow
previous(DayOfWeek dow)der jüngste dow strikt vor dem Datum
previousOrSame(DayOfWeek dow)heute, wenn es dow ist, sonst vorheriger dow
dayOfWeekInMonth(int ord, DayOfWeek dow)n-ter Wochentag des Monats: dayOfWeekInMonth(3, MONDAY) → 3. Montag
firstInMonth(DayOfWeek dow)erster dow des Monats (entspricht dayOfWeekInMonth(1, dow))
lastInMonth(DayOfWeek dow)letzter dow des Monats

Die obere Hälfte beantwortet „Was ist der erste/letzte X?" und die untere Hälfte „Was ist der nächste/vorherige X?". Verketten Sie sie, wenn die Frage komplexer ist:

LocalDate firstMondayNextMonth = today.with(firstDayOfNextMonth()).with(nextOrSame(DayOfWeek.MONDAY));

Das bedeutet: „der erste Montag am oder nach dem ersten des nächsten Monats." Von links nach rechts lesen; jedes with ist ein Schritt.

Anwenden mit with(adjuster)

LocalDate today = LocalDate.now();
LocalDate eom = today.with(lastDayOfMonth());
LocalDate nextMonday = today.with(next(DayOfWeek.MONDAY));
LocalDate thirdFriday = today.with(dayOfWeekInMonth(3, DayOfWeek.FRIDAY));

with existiert auf jedem Temporal: LocalDate, LocalDateTime, ZonedDateTime, sogar OffsetDateTime. Der Adjuster berührt nur die Datumskomponenten — die Anwendung von lastDayOfMonth() auf ein LocalDateTime lässt die Uhrzeit unverändert.

Adjuster sind total: Sie liefern immer ein Ergebnis. Es gibt keinen Ausnahmepfad für „Was, wenn heute nicht im richtigen Monat ist?" — lastDayOfMonth() vom 31. Januar gibt weiterhin den 31. Januar zurück (der letzte Tag ist er selbst).

Lambda-Adjuster

Da TemporalAdjuster ein @FunctionalInterface ist, können Sie eigene mit einem Lambda schreiben:

TemporalAdjuster nextWorkingDay = t -> {
  LocalDate d = LocalDate.from(t).plusDays(1);
  while (d.getDayOfWeek() == DayOfWeek.SATURDAY || d.getDayOfWeek() == DayOfWeek.SUNDAY) {
    d = d.plusDays(1);
  }
  return d;
};

LocalDate friday = LocalDate.of(2025, 11, 7);
LocalDate monday = friday.with(nextWorkingDay);                 // 2025-11-10

Das Muster: Den eingehenden Temporal in den gewünschten Datumstyp umwandeln (LocalDate.from(t)), das neue Datum berechnen, zurückgeben. Der Rückgabetyp ist Temporal (das Interface), aber das JDK akzeptiert den konkreten Rückgabewert.

Für den einmaligen Gebrauch ist das übertrieben — schreiben Sie die Logik einfach direkt an die Aufrufstelle. Für eine Berechnung, die Sie an mehreren Stellen verwenden (nächster Werktag, letzter Tag des Quartals, beobachteter Feiertag), hält sie die Aufrufstellen lesbar, wenn Sie sie als Adjuster bündeln.

ofDateAdjuster für den einfachen Lambda-Fall

Wenn Ihr Adjuster nur mit LocalDate arbeitet (der häufigste Fall), ist TemporalAdjusters.ofDateAdjuster(UnaryOperator<LocalDate>) die sauberere Factory:

TemporalAdjuster nextWorkingDay = TemporalAdjusters.ofDateAdjuster(d -> {
  LocalDate result = d.plusDays(1);
  while (result.getDayOfWeek().getValue() > 5) {
    result = result.plusDays(1);
  }
  return result;
});

Das Lambda nimmt ein LocalDate und gibt eines zurück. Die Factory verpackt es als TemporalAdjuster. Das ist das Mittel der Wahl in 90 % der Fälle beim Schreiben eigener Adjuster.

Ein ausgearbeitetes Beispiel: Geschäftsdaten, Feiertage, Periodenende

Das folgende Programm verwendet Adjuster für den Buchhaltungskalender: Monatsende für die Abrechnung, letzter Geschäftstag des Monats für den Cash Close, erster Montag des nächsten Monats für ein regelmäßiges Planungsmeeting, einen feiertagsbewussten „nächsten Werktag"-Adjuster und die Berechnung des Quartalsendes.

java— editable, runs on the server

Was aus der Ausführung zu entnehmen ist:

  • Die eingebauten Adjuster deckten die Grenzfälle ab (firstDayOfMonth, lastDayOfMonth, firstDayOfYear usw.) ohne jegliche Arithmetik Ihrerseits. Für „dieses Datum auf den Anfang/Ende seines Monats oder Jahres runden" sind sie das richtige Werkzeug — klarer als withDayOfMonth(1)-Berechnungen per Hand und immun gegen Überraschungen bei der Monatslänge.
  • next(MONDAY) und previous(FRIDAY) lieferten strikt verschiedene Daten; nextOrSame(TUESDAY) an einem Dienstag lieferte das heutige Datum. Merken Sie sich die Unterscheidung strikt-vs-oder-gleich; sie ist die Quelle der meisten „um eine Woche daneben"-Fehler, wenn das Ausgangsdatum zufällig auf den Zielwochentag fällt.
  • Das verkettete firstDayOfNextMonth().nextOrSame(MONDAY) drückte „den ersten Montag am oder nach dem ersten des nächsten Monats" in zwei Lesevorgängen aus. Die Kette ist eine Zeile; das handgefertigte Äquivalent sind sechs. Das Verketten von Adjustern ist die idiomatische Art, sie zu kombinieren.
  • NEXT_BUSINESS_DAY übersprang das Wochenende und einen Feiertag in einem Schritt. Die HOLIDAYS-Menge war ein synthetisches Zwei-Elemente-Beispiel; eine echte Implementierung würde aus einem Dienst laden. Die Adjuster-Form ist dieselbe — wickeln Sie die Schleife in TemporalAdjusters.ofDateAdjuster(...) und Sie können ihn überall in today.with(NEXT_BUSINESS_DAY)-Aufrufen einsetzen.
  • END_OF_QUARTER war ein einzeiliger benutzerdefinierter Adjuster, der den dritten Monat des Quartals des Datums auswählte und lastDayOfMonth() anwendete. Der Punkt: Komplexe Domänenoperationen gehören in benannte TemporalAdjuster-Konstanten, bei denen die Aufrufstelle someDate.with(END_OF_QUARTER) liest, anstatt einen sechszeiligen Arithmetikblock einzubetten. Halten Sie die Kalenderlogik an einem Ort.

Was kommt als nächstes

TemporalAdjusters schließen die moderne java.time-API ab. Die letzten beiden Kapitel dieses Teils behandeln die Legacy-Typen, denen Sie in älterem Code begegnen: Java Legacy Date Class für das ursprüngliche java.util.Date und Java Calendar Class für java.util.Calendar. Beide sind noch aus Kompatibilitätsgründen vorhanden; beide haben einen sauberen Konvertierungspfad zu java.time.

Übungen

Übung
Sie benötigen 'den ersten Montag des nächsten Monats' ausgehend von einem beliebigen Datum. Welcher Ausdruck liefert diesen Wert am idiomatischsten?
Sie benötigen 'den ersten Montag des nächsten Monats' ausgehend von einem beliebigen Datum. Welcher Ausdruck liefert diesen Wert am idiomatischsten?
Was this page helpful?