W3docs

La Classe Calendar di Java

La classe legacy java.util.Calendar e GregorianCalendar — come si relazionano con java.time.

java.util.Calendar è la seconda metà della coppia di data/ora legacy. Mentre java.util.Date è solo un wrapper attorno a un long di millisecondi epoch, Calendar è ciò che sa in quale anno, mese e giorno cade quel millisecondo. È stato aggiunto in Java 1.1 per estrarre l'aritmetica del calendario da Date — ecco perché la maggior parte degli accessor di campo di Date sono deprecati.

Nel codice moderno dovresti usare java.time. Ma Calendar appare ancora: nei vecchi percorsi di codice, nelle librerie scritte prima di Java 8 e nei driver JDBC che non sono stati aggiornati. Devi saperlo leggere, fare il bridge e andare avanti. Questa pagina spiega come creare un Calendar, leggere i suoi campi in modo sicuro (attenzione ai mesi a base zero), fare aritmetica con il calendario e — soprattutto — fare il bridge verso l'API moderna.

Calendar è astratto

Calendar stesso è una classe astratta. Non chiami mai new Calendar(...). Ottieni un'istanza tramite la factory:

Calendar cal = Calendar.getInstance();

Questo restituisce una sottoclasse concreta — quasi sempre GregorianCalendar — precaricata con l'ora corrente, il fuso orario predefinito e il locale predefinito. Puoi essere esplicito se necessario:

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

GregorianCalendar ha anche costruttori pubblici, ma la factory è la convenzione.

Costanti di campo

Calendar espone tutto attraverso costanti di campo intere e un generico get(int field):

CampoSignificatoIntervallo
Calendar.YEARAnnoanno completo, es. 2026
Calendar.MONTHMese0–11 (Gennaio = 0)
Calendar.DAY_OF_MONTHGiorno del mese1–31
Calendar.DAY_OF_WEEKGiorno della settimana1–7 (Domenica = 1)
Calendar.HOUR_OF_DAYOra0–23
Calendar.MINUTEMinuto0–59
Calendar.SECONDSecondo0–59
Calendar.MILLISECONDMilli0–999

Due trappole si trovano in questa tabella: MONTH è a base zero (Calendar.JANUARY == 0) e DAY_OF_WEEK inizia dalla domenica. I bug di offset di uno nel codice legacy quasi sempre risalgono a queste.

Impostazione e aritmetica

set accetta un campo e un valore; add esegue un'aritmetica consapevole del calendario che trasferisce l'overflow nei campi più grandi:

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 fa la stessa cosa campo per campo ma non riporta il riporto nei campi più grandi — roll(DAY_OF_MONTH, 5) sul 30 maggio dà il 4 maggio, non il 4 giugno. È raramente quello che si vuole.

Le istanze di Calendar sono mutabili, quindi passarne una a un metodo significa consegnare un handle attivo. Clonala prima di esporla, come faresti con un Date.

Il bridge verso java.time

L'unico motivo per cui oggi si tocca Calendar è per uscirne. Due metodi lo fanno:

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

Da ZonedDateTime hai a disposizione l'intera API moderna. Andando nella direzione opposta:

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

GregorianCalendar.from(ZonedDateTime) è la conversione supportata. Evita i round-trip attraverso Date.

Esempio pratico

L'esempio qui sotto mostra le due cose che farai con Calendar nel codice reale: leggere i campi da un'istanza legacy e fare il bridge verso java.time per qualsiasi cosa non banale.

java— editable, runs on the server

Cosa ricavare dall'esecuzione:

  • Calendar.MONTH per maggio stampa 4. I mesi a base zero sono la singola maggiore fonte di bug nel codice di date legacy.
  • getInstance(TimeZone) lega l'istanza a una zona — diversamente da Date, che non ne ha.
  • add(MONTH, 1) comprende la lunghezza dei mesi; ottieni il giorno corretto nel mese successivo anche se i mesi non sono tutti da 30 giorni.
  • cal.toInstant().atZone(cal.getTimeZone().toZoneId()) è il bridge in una riga verso java.time.
  • GregorianCalendar.from(ZonedDateTime) ti permette di restituire un Calendar a una vecchia API senza perdere la zona.

Cosa c'è dopo

Questo chiude la Parte 14 — Data e Ora. La prossima è la Parte 15, Multithreading e Concorrenza, che inizia con Multithreading in Java — il modello che ha plasmato ogni altra API in questo libro.

Pratica
Un Calendar impostato al 29 maggio 2026 riporta cal.get(Calendar.MONTH). Quale valore viene restituito?
Un Calendar impostato al 29 maggio 2026 riporta cal.get(Calendar.MONTH). Quale valore viene restituito?
Was this page helpful?