W3docs

La classe Calendar en Java

La classe legacy java.util.Calendar et GregorianCalendar — leur rôle et leur relation avec java.time.

java.util.Calendar est la seconde moitié du duo date/heure historique. Là où java.util.Date n'est qu'un wrapper autour d'un long de millisecondes depuis l'époque, Calendar est ce qui sait à quelle année, quel mois et quel jour correspond cette milliseconde. Elle a été ajoutée dans Java 1.1 pour extraire l'arithmétique calendaire de Date — c'est pourquoi la plupart des accesseurs de champs de Date sont dépréciés.

Dans le code moderne, vous devriez vous tourner vers java.time. Mais Calendar apparaît encore : dans d'anciens chemins de code, dans des bibliothèques écrites avant Java 8, et dans des drivers JDBC qui n'ont pas été mis à jour. Vous devez savoir la lire, la convertir et passer à autre chose. Cette page explique comment créer un Calendar, lire ses champs en toute sécurité (attention au mois basé sur zéro), effectuer de l'arithmétique calendaire et — surtout — le convertir vers l'API moderne.

Calendar est abstraite

Calendar elle-même est une classe abstraite. Vous n'appelez jamais new Calendar(...). Vous obtenez une instance via la fabrique :

Calendar cal = Calendar.getInstance();

Cela renvoie une sous-classe concrète — presque toujours GregorianCalendar — préchargée avec l'heure actuelle, le fuseau horaire par défaut et la locale par défaut. Vous pouvez être explicite si nécessaire :

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

GregorianCalendar possède également des constructeurs publics, mais la fabrique est la convention.

Constantes de champs

Calendar expose tout via des constantes de champs entiers et un get(int field) générique :

ChampSignificationPlage
Calendar.YEARAnnéeannée complète, ex. 2026
Calendar.MONTHMois0–11 (Janvier = 0)
Calendar.DAY_OF_MONTHJour du mois1–31
Calendar.DAY_OF_WEEKJour de la semaine1–7 (Dimanche = 1)
Calendar.HOUR_OF_DAYHeure0–23
Calendar.MINUTEMinute0–59
Calendar.SECONDSeconde0–59
Calendar.MILLISECONDMillisecondes0–999

Deux pièges se cachent dans ce tableau : MONTH est basé sur zéro (Calendar.JANUARY == 0) et DAY_OF_WEEK commence au dimanche. Les bugs de décalage d'un dans le code legacy se tracent presque toujours ici.

Définition et arithmétique

set prend un champ et une valeur ; add effectue une arithmétique calendaire qui propage les débordements vers les champs plus grands :

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 fait la même chose champ par champ mais ne propage pas vers les champs plus grands — roll(DAY_OF_MONTH, 5) sur le 30 mai donne le 4 mai, pas le 4 juin. C'est rarement ce que vous voulez.

Les instances de Calendar sont mutables, donc passer une instance à une méthode revient à donner un accès direct à l'objet. Clonez avant d'exposer, de la même façon que vous le feriez avec un Date.

Le pont vers java.time

L'intérêt de manipuler Calendar aujourd'hui est d'en sortir. Deux méthodes permettent cela :

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

À partir de ZonedDateTime, vous avez accès à toute l'API moderne. Dans l'autre sens :

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

GregorianCalendar.from(ZonedDateTime) est la conversion supportée. Évitez de passer par Date comme intermédiaire.

Exemple pratique

L'exemple ci-dessous illustre les deux choses que vous ferez avec Calendar dans du vrai code : lire des champs depuis une instance legacy, et faire le pont vers java.time pour toute opération non triviale.

java— editable, runs on the server

Ce qu'il faut retenir de l'exécution :

  • Calendar.MONTH pour mai affiche 4. Les mois basés sur zéro sont la principale source de bugs dans le code de dates legacy.
  • getInstance(TimeZone) lie l'instance à un fuseau horaire — différent de Date, qui n'en possède pas.
  • add(MONTH, 1) tient compte de la durée des mois ; vous obtenez le bon jour dans le mois suivant, même si les mois n'ont pas tous 30 jours.
  • cal.toInstant().atZone(cal.getTimeZone().toZoneId()) est le pont en une ligne vers java.time.
  • GregorianCalendar.from(ZonedDateTime) vous permet de retourner un Calendar à une ancienne API sans perdre le fuseau horaire.

La suite

Cela clôt la Partie 14 — Date et Heure. La suite est la Partie 15, Multithreading et Concurrence, qui commence par Le multithreading en Java — le modèle qui a influencé toutes les autres API de ce livre.

Pratique
Un Calendar défini au 29 mai 2026 renvoie cal.get(Calendar.MONTH). Quelle valeur est retournée ?
Un Calendar défini au 29 mai 2026 renvoie cal.get(Calendar.MONTH). Quelle valeur est retournée ?
Was this page helpful?