W3docs

Java TemporalAdjusters

Calcola date relative in Java con TemporalAdjusters: firstDayOfMonth, next, previous e aggiustatori personalizzati.

plusDays(7) aggiunge sette giorni. withDayOfMonth(15) salta al 15. Questi due metodi coprono i casi semplici. Un TemporalAdjuster è un oggetto a forma di funzione che si passa a Temporal.with(adjuster) per gestire i casi in cui la nuova data dipende da quella corrente in modo più complesso: "il primo lunedì del mese prossimo," "l'ultimo giorno di questo trimestre," "il Ringraziamento americano dell'anno prossimo."

L'interfaccia ha un solo metodo:

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

Di solito non la si implementa direttamente. La classe java.time.temporal.TemporalAdjusters (nota la sAdjusters, plurale) è un kit di circa una dozzina di aggiustatori integrati che coprono i casi comuni, e LocalDate.with(adjuster) è il modo per applicarli.

Il catalogo integrato

Importa staticamente; il codice risulta più leggibile in questo modo:

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

Poi:

AggiustatoreEffetto
firstDayOfMonth()giorno → primo giorno dello stesso mese
lastDayOfMonth()giorno → ultimo giorno dello stesso mese
firstDayOfNextMonth()giorno → primo giorno del mese successivo
firstDayOfYear()giorno → 1° gennaio dello stesso anno
lastDayOfYear()giorno → 31 dicembre dello stesso anno
firstDayOfNextYear()giorno → 1° gennaio dell'anno successivo
next(DayOfWeek dow)il prossimo dow strettamente dopo la data
nextOrSame(DayOfWeek dow)oggi se è dow, altrimenti il prossimo dow
previous(DayOfWeek dow)il dow più recente strettamente prima della data
previousOrSame(DayOfWeek dow)oggi se è dow, altrimenti il precedente dow
dayOfWeekInMonth(int ord, DayOfWeek dow)l'ennesimo giorno della settimana nel mese: dayOfWeekInMonth(3, MONDAY) → 3° lunedì
firstInMonth(DayOfWeek dow)primo dow del mese (equivalente a dayOfWeekInMonth(1, dow))
lastInMonth(DayOfWeek dow)ultimo dow del mese

Le due metà rispondono a "qual è il primo/ultimo X" (metà superiore) e "qual è il prossimo/precedente X" (metà inferiore). Concatenali quando la domanda è più complessa:

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

Questo significa "il primo lunedì a partire dal primo del mese prossimo." Leggi da sinistra a destra; ogni with è un passaggio.

Applicare con 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 esiste su ogni Temporal: LocalDate, LocalDateTime, ZonedDateTime, anche OffsetDateTime. L'aggiustatore tocca solo le componenti della data — applicare lastDayOfMonth() a un LocalDateTime lascia invariata l'ora.

Gli aggiustatori sono totali: restituiscono sempre un risultato. Non esiste un percorso di eccezione "cosa succede se oggi non è nel mese giusto" — lastDayOfMonth() a partire dal 31 gennaio è ancora il 31 gennaio (l'ultimo giorno è se stesso).

Aggiustatori lambda

Poiché TemporalAdjuster è una @FunctionalInterface, puoi scriverne uno tuo con una lambda:

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

Il pattern: converti il Temporal in ingresso nel tipo di data che vuoi (LocalDate.from(t)), calcola la nuova data, restituiscila. Il tipo di ritorno è Temporal (l'interfaccia), ma il JDK accetta il tipo concreto restituito.

Per un uso occasionale questo è eccessivo — basta inserire la logica direttamente nel punto di chiamata. Per un calcolo che userai in più punti (giorno lavorativo successivo, ultimo giorno del trimestre, festività osservata), impacchettarlo come aggiustatore mantiene leggibili i punti di chiamata.

ofDateAdjuster per il caso lambda semplice

Se il tuo aggiustatore lavora solo con LocalDate (il caso comune), TemporalAdjusters.ofDateAdjuster(UnaryOperator<LocalDate>) è la factory più pulita:

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

La lambda prende e restituisce una LocalDate. La factory la incapsula come TemporalAdjuster. Questo è ciò che si usa nel 90% dei casi quando si scrivono aggiustatori personalizzati.

Un esempio pratico: date lavorative, festività, fine periodo

Il programma seguente usa gli aggiustatori per il calendario contabile: fine mese per la fatturazione, ultimo giorno lavorativo del mese per la chiusura di cassa, il primo lunedì del mese successivo per una riunione di pianificazione regolare, un aggiustatore "prossimo giorno lavorativo" che tiene conto delle festività, e il calcolo della fine del trimestre.

java— editable, runs on the server

Cosa trarre dall'esecuzione:

  • Gli aggiustatori integrati hanno coperto i casi limite (firstDayOfMonth, lastDayOfMonth, firstDayOfYear, ecc.) senza alcuna aritmetica da parte tua. Per "questa data allineata all'inizio/fine del suo mese o anno," sono lo strumento giusto — più chiari del calcolo manuale con withDayOfMonth(1), e immuni alle sorprese sulla lunghezza del mese.
  • next(MONDAY) e previous(FRIDAY) hanno restituito date strettamente diverse; nextOrSame(TUESDAY) su un martedì ha restituito oggi. Memorizza la distinzione strict-vs-or-same; è la fonte della maggior parte dei bug "sfasamento di una settimana" quando la data di partenza cade proprio nel giorno della settimana target.
  • La concatenazione firstDayOfNextMonth().nextOrSame(MONDAY) ha espresso "il primo lunedì a partire dal primo del mese prossimo" in due letture. La catena è una riga; l'equivalente manuale è sei. Concatenare gli aggiustatori è il modo idiomatico per comporli.
  • NEXT_BUSINESS_DAY ha saltato il fine settimana e una festività in un colpo solo. Il set HOLIDAYS era un esempio sintetico con due elementi; un'implementazione reale li caricherebbe da un servizio. La forma dell'aggiustatore è la stessa — incapsula il ciclo in TemporalAdjusters.ofDateAdjuster(...) e puoi usarlo nelle chiamate today.with(NEXT_BUSINESS_DAY) ovunque.
  • END_OF_QUARTER era un aggiustatore personalizzato di una riga che selezionava il terzo mese del trimestre della data e applicava lastDayOfMonth(). Il punto: le operazioni di dominio complesse appartengono a costanti TemporalAdjuster con nome, dove il punto di chiamata si legge come someDate.with(END_OF_QUARTER) invece di inserire un blocco aritmetico di sei righe. Tieni la logica del calendario in un unico posto.

Cosa fare dopo

TemporalAdjusters chiude la moderna API java.time. Gli ultimi due capitoli di questa parte coprono i tipi legacy che incontrerai nel codice più vecchio: Java Legacy Date Class per l'originale java.util.Date, e Java Calendar Class per java.util.Calendar. Entrambi sono ancora presenti per compatibilità; entrambi hanno un percorso di conversione pulito verso java.time.

Pratica

Pratica
Hai bisogno di 'il primo lunedì del mese prossimo' a partire da una data qualsiasi. Quale espressione restituisce quel valore in modo più idiomatico?
Hai bisogno di 'il primo lunedì del mese prossimo' a partire da una data qualsiasi. Quale espressione restituisce quel valore in modo più idiomatico?
Was this page helpful?