Fechas y hora
Zonas horarias: distingue instantes, fechas y horarios recurrentes
Elige la representación adecuada y prueba horas locales ausentes o repetidas.
Decide qué significa el valor
Un evento pasado, un cumpleaños y «cada día a las 09:00 de Madrid» representan datos distintos:
- Instante: guarda un timestamp con unidad documentada o texto con desplazamiento explícito. Muéstralo en la zona necesaria.
- Fecha de calendario: conserva año, mes y día si no le corresponde una hora ni zona. Inventar un instante a medianoche UTC puede desplazar la fecha al mostrarla en otro lugar.
- Horario local: conserva hora, zona IANA, recurrencia y criterio para horas ausentes o repetidas. Una hora UTC fija no conserva «09:00 Madrid» cuando cambia el desplazamiento.
El conversor de timestamp presenta un instante en UTC y en la zona del dispositivo. Su entrada de fecha usa esa zona. El conversor de zonas permite comparar zonas seleccionadas; para los ejemplos reproducibles siguientes, parte de instantes UTC explícitos. Estas herramientas no son un programador de tareas recurrentes.
Dos instantes alrededor de un cambio de primavera
const format = new Intl.DateTimeFormat('en-GB', {
timeZone: 'Europe/Madrid', hour: '2-digit', minute: '2-digit',
hourCycle: 'h23', timeZoneName: 'longOffset'
});
console.log(format.format(new Date('2024-03-31T00:30:00Z')));
// 01:30 GMT+01:00
console.log(format.format(new Date('2024-03-31T01:30:00Z')));
// 03:30 GMT+02:00
Ha pasado una hora, aunque la hora mostrada avance dos. En esa transición no existió la hora local intermedia. Una entrada local 02:30 necesita un criterio: rechazarla o resolverla con una regla documentada. No todas las regiones cambian una hora ni todas usan horario de verano.
En el ejemplo de otoño, 2024-10-27T00:30:00Z y 2024-10-27T01:30:00Z muestran 02:30 en Madrid con desplazamientos distintos. La hora local sin desplazamiento no los distingue.
Descarga las comprobaciones y ejecuta node date-checks.mjs. Se verifican horas y desplazamientos con formatToParts, sin depender de la puntuación del texto formateado.
Una zona no es un desplazamiento
Europe/Madrid identifica un conjunto de reglas; +02:00 es un desplazamiento concreto. Para historial y programación futura, necesitas la zona y los datos temporales aplicables. Abreviaturas como CST pueden corresponder a varias regiones. Mantén actualizados los datos de zonas del entorno: el nombre no garantiza que las reglas políticas futuras sean invariables.
El tipo de base de datos depende del significado
En PostgreSQL, timestamp with time zone (timestamptz) representa un instante y lo muestra en la zona de sesión. No conserva el nombre IANA original; guárdalo aparte si lo necesitas. timestamp without time zone sirve para una fecha/hora deliberadamente local: no adquiere una zona porque un cliente la espere. Para un valor de sólo fecha puede corresponder una columna date.
No traslades automáticamente estos consejos a otro motor: sus rangos y reglas pueden ser distintos. Prueba el driver, el tipo de columna y la serialización reales.
Comprobaciones concretas
Incluye una fecha ordinaria, una hora ausente, otra repetida y una fecha cercana a medianoche UTC. Prueba con el dispositivo en UTC y en otra zona. Para recurrencias, calcula la siguiente aparición local, no simplemente el instante anterior más 24 horas. Documenta si un valor de API sin zona es una fecha, una hora local o un error.
Fuentes: MDN Intl.DateTimeFormat, MDN Date, tipos temporales de PostgreSQL, base de zonas IANA.