Apex Academy
Módulo 1·04·22 min

Date, Time y Datetime

Tres tipos para el tiempo, y una zona horaria que explica el 90 % de los «pero si en el informe salía otro día».

En Admin esLos campos Date, Time y Date/Time, y la zona horaria de los informes

✓ En esta sub-lección

  1. 01Elegir entre Date, Time y Datetime según lo que realmente se necesita saber.
  2. 02Crear fechas y operar con ellas sin escribirlas como texto.
  3. 03Explicar por qué una fecha parece cambiar según quién la mira.

La nutria: ¿Te acuerdas? · Repaso de la lección 3

En rawName.trim().toLowerCase(), ¿qué método se ejecuta primero?

En el asistente de campos hay tres opciones distintas para el tiempo: Date, Time y Date/Time. Elegiste mal alguna vez y lo pagaste en un informe. Apex tiene exactamente los mismos tres tipos, con los mismos nombres y las mismas consecuencias.

Datetime createdAt = Datetime.now();

EL MISMO DATO, TRES LECTURAS

  • guardado—
  • en Madrid16/03 00:30
  • en Londres—

Paso 1 de 4

Un pedido se crea a las 00:30 del 16 de marzo, hora de Madrid. Datetime guarda un instante exacto: día y hora.

La pregunta que decide el tipo: ¿necesito el día, el momento del día, o el instante exacto?

Crear una fecha

Las fechas no se escriben entre comillas. Un texto entre comillas es texto, aunque parezca una fecha, y no sabe sumar días. Para crear una fecha se usa newInstance(), indicando año, mes y día por separado; para la de hoy, today().

Apex
Date closeDate = Date.newInstance(2026, 3, 15);   // año, mes, día
Date today = Date.today();

Datetime createdAt = Datetime.now();
Datetime meeting = Datetime.newInstance(2026, 3, 15, 14, 30, 0);

Time reminder = Time.newInstance(9, 0, 0, 0);    // h, min, s, ms
El mes va de 1 a 12, como esperas. Es de las pocas cosas en programación que no empieza en 0.

Hacer cuentas con fechas

Sumar un mes a una fecha no es sumar 30 días, y calcular los días entre dos fechas a mano es una invitación al bug. Los tipos de fecha traen métodos que ya saben de meses de 28 días y de años bisiestos.

MétodoQué devuelveEjemplo
addDays(n) / addMonths(n) / addYears(n)Date: una fecha nueva desplazada.closeDate.addMonths(12)
daysBetween(otraFecha)Integer: días de diferencia (negativo si es anterior).today.daysBetween(closeDate)
monthsBetween(otraFecha)Integer: meses completos de diferencia.start.monthsBetween(end)
year() / month() / day()Integer: la parte que pides.closeDate.year()
addDays() sobre un DatetimeDatetime: mismo instante, otro día.createdAt.addHours(2)
format()String: la fecha lista para mostrar.createdAt.format()
Apex
Date signed = Date.newInstance(2026, 1, 31);
Date renewal = signed.addMonths(1);        // 2026-02-28, no 2026-02-31

Date today = Date.today();
Integer daysToRenewal = today.daysBetween(renewal);
Igual que los String, las fechas son inmutables: addMonths() devuelve una fecha nueva y deja la original intacta.

La nutria: Date.today().daysBetween(): una cadena que empieza en el tipo

Cuando yo era Admin, en una fórmula escribía Renewal_Date__c - TODAY() y ya tenía los días. En Apex, las dos líneas de arriba (Date today = Date.today(); y luego today.daysBetween(renewal)) se suelen escribir en una sola: Date.today().daysBetween(renewal). Es el encadenado de la sub-lección de String: Date.today() se le pide al tipo Date y devuelve un Date (el de hoy), y a ESE Date le pides daysBetween(). A mí me costó leerlo al principio, y mi truco fue desarmarlo en dos líneas como arriba: es exactamente lo mismo. Y un tropiezo que tuve: la fecha desde la que cuentas va delante del punto; al revés, el número sale negativo.
Apex
Date closeDate = Date.newInstance(2026, 12, 31);

Integer daysLeft = Date.today().daysBetween(closeDate);    // cadena: hoy → días hasta el cierre
Integer closeYear = closeDate.addDays(30).year();           // cadena: +30 días → su año
String closeLabel = String.valueOf(closeDate.addMonths(1)); // anidado: la fecha nueva, como texto
closeYear vale 2027: al sumar 30 días al 31 de diciembre se cambia de año, y year() lee el año de la fecha NUEVA, no de closeDate.

La zona horaria, de una vez por todas

Un Datetime se guarda siempre en y se muestra en la zona horaria del usuario que lo mira. Por eso una reunión creada a las 00:30 en Madrid puede aparecer como el día anterior para un compañero en Londres: el instante es el mismo, la etiqueta cambia.

La nutria: El informe que «estaba mal»

¿Te acuerdas de aquel informe agrupado por CreatedDate en el que un pedido de última hora de la noche aparecía en el día siguiente? A mí me pasó, y abrí un caso a soporte pensando que era un bug. No estaba mal: agrupaba en GMT mientras yo miraba en hora local. En Apex esa decisión la tomas tú, y de forma explícita: date() te da el día en la zona del usuario y dateGMT() te lo da en GMT.
Apex
Datetime createdAt = Datetime.now();

Date localDay = createdAt.date();       // día según la zona del usuario
Date gmtDay = createdAt.dateGMT();      // día en GMT
String shown = createdAt.format();      // texto, ya en la zona del usuario