W3docs

Clase Calendar de Java

La clase heredada java.util.Calendar y GregorianCalendar: cómo se relacionan con java.time.

java.util.Calendar es la segunda mitad del par de fecha/hora heredado. Mientras que java.util.Date es simplemente un envoltorio alrededor de un long de milisegundos epoch, Calendar es lo que sabe en qué año, mes y día cae ese milisegundo. Se añadió en Java 1.1 para extraer la aritmética de calendario de Date — por eso la mayoría de los accesores de campo de Date están obsoletos.

En código moderno deberías usar java.time. Pero Calendar sigue apareciendo: en rutas de código antiguo, en bibliotecas escritas antes de Java 8 y en controladores JDBC que no han sido actualizados. Necesitas leerlo, hacer el puente y seguir adelante. Esta página explica cómo crear un Calendar, leer sus campos de forma segura (cuidado con el mes basado en cero), hacer aritmética de calendario y — lo más importante — hacer el puente hacia la API moderna.

Calendar es abstracta

Calendar en sí es una clase abstracta. Nunca llamas new Calendar(...). Obtienes una instancia a través del factory:

Calendar cal = Calendar.getInstance();

Esto devuelve una subclase concreta — casi siempre GregorianCalendar — precargada con la hora actual, la zona horaria predeterminada y el locale predeterminado. Puedes ser explícito si lo necesitas:

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

GregorianCalendar también tiene constructores públicos, pero el factory es la convención.

Constantes de campo

Calendar expone todo a través de constantes de campo enteras y un get(int field) genérico:

CampoSignificadoRango
Calendar.YEARAñoaño completo, p. ej. 2026
Calendar.MONTHMes0–11 (enero = 0)
Calendar.DAY_OF_MONTHDía del mes1–31
Calendar.DAY_OF_WEEKDía de la semana1–7 (domingo = 1)
Calendar.HOUR_OF_DAYHora0–23
Calendar.MINUTEMinuto0–59
Calendar.SECONDSegundo0–59
Calendar.MILLISECONDMilisegundo0–999

Dos trampas se esconden en esta tabla: MONTH es basado en cero (Calendar.JANUARY == 0) y DAY_OF_WEEK empieza en domingo. Los errores de desfase por uno en código heredado casi siempre tienen su origen aquí.

Asignación y aritmética

set toma un campo y un valor; add hace aritmética consciente del calendario que desborda en campos mayores:

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 hace lo mismo campo por campo pero no se lleva a campos mayores — roll(DAY_OF_MONTH, 5) en el 30 de mayo da el 4 de mayo, no el 4 de junio. Raramente es lo que quieres.

Las instancias de Calendar son mutables, por lo que pasar una a un método significa entregar un identificador activo. Clona antes de exponer, de la misma forma que harías con un Date.

El puente hacia java.time

El único propósito de trabajar con Calendar hoy en día es salir de él. Dos métodos lo hacen posible:

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

Desde ZonedDateTime tienes toda la API moderna. En sentido inverso:

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

GregorianCalendar.from(ZonedDateTime) es la conversión compatible. Evita el ida y vuelta a través de Date.

Ejemplo práctico

El ejemplo siguiente muestra las dos cosas que harás con Calendar en código real: leer campos de una instancia heredada y hacer el puente a java.time para cualquier cosa no trivial.

java— editable, runs on the server

Lo que hay que extraer de la ejecución:

  • Calendar.MONTH para mayo imprime 4. Los meses basados en cero son la mayor fuente de errores en el código heredado de fechas.
  • getInstance(TimeZone) vincula la instancia a una zona — diferente de Date, que no tiene ninguna.
  • add(MONTH, 1) entiende la duración de los meses; obtienes el día correcto del mes siguiente aunque los meses no sean todos de 30 días.
  • cal.toInstant().atZone(cal.getTimeZone().toZoneId()) es el puente de una línea hacia java.time.
  • GregorianCalendar.from(ZonedDateTime) te permite devolver un Calendar a una API antigua sin perder la zona.

Qué sigue

Esto cierra la Parte 14 — Fecha y Hora. A continuación viene la Parte 15, Multihilo y Concurrencia, comenzando con Multithreading en Java — el modelo que ha dado forma a todas las demás APIs de este libro.

Práctica
Un Calendar establecido al 29 de mayo de 2026 devuelve cal.get(Calendar.MONTH). ¿Qué valor se obtiene?
Un Calendar establecido al 29 de mayo de 2026 devuelve cal.get(Calendar.MONTH). ¿Qué valor se obtiene?
Was this page helpful?