Introducción: por qué el tiempo es un dolor
\n\nCualquiera que haya escrito código en JavaScript al menos una vez se ha enfrentado a este dolor. Le muestras al usuario la hora 12:00, y él escribe: «Yo tengo las 14:00, todo está roto». O guardas una fecha en la base de datos y, al cargarla, se desplaza una hora hacia atrás. ¿Te suena?
\n\nTrabajar con zonas horarias en JavaScript es ese tema que muchos desarrolladores posponen «para después». Y es una lástima. Porque si no lo resuelves de inmediato, luego tendrás que reescribir la mitad de la aplicación.
\n\nEn este artículo te contaré cómo trabajar correctamente con zonas horarias en JS, mostraré ejemplos reales de código y te daré algunos trucos que te ahorrarán horas de depuración. ¡Allá vamos!
\n\n¿Por qué JavaScript trabaja tan extraño con las fechas?
\n\nEmpecemos por lo principal: el objeto Date en JavaScript no es, por decirlo suavemente, un regalo. Almacena el tiempo en milisegundos desde el 1 de enero de 1970 UTC. Y todo estaría bien, pero:
- \n
getMonth()devuelve los meses de 0 a 11 (enero es 0, diciembre es 11) \n - Los métodos
getHours(),getMinutes()devuelven la hora en la zona horaria local del usuario \n - Y los métodos
getUTCHours(),getUTCMinutes()— en UTC \n
Y aquí es donde comienza la confusión. Supongamos que escribes:
\n\nconst now = new Date();\nconsole.log(now.getHours()); // 14 — si estás en MSK\nconsole.log(now.getUTCHours()); // 11 — UTC\n\nSi guardas now en la base de datos y luego lo recuperas en el servidor en otra zona horaria, obtendrás un lío. Por lo tanto, la primera regla para trabajar con fechas y zonas horarias en JavaScript es: siempre almacena la hora en UTC y conviértela en el cliente.
Intl.DateTimeFormat: el salvador integrado
\n\nMuchos no lo saben, pero en JavaScript moderno hay una potente API integrada para trabajar con el formateo de fechas teniendo en cuenta la zona horaria. Es Intl.DateTimeFormat. Soporta todas las zonas horarias principales y sabe formatear fechas de manera elegante.
Ejemplo básico
\n\nconst date = new Date('2025-03-15T12:00:00Z');\n\nconst formatter = new Intl.DateTimeFormat('es-ES', {\n timeZone: 'America/New_York',\n year: 'numeric',\n month: 'long',\n day: 'numeric',\n hour: '2-digit',\n minute: '2-digit'\n});\n\nconsole.log(formatter.format(date)); \n// "15 de marzo de 2025, 08:00" — hora en Nueva York\n\nObserva: pasamos la fecha en UTC (letra Z al final), y Intl.DateTimeFormat la convierte automáticamente a la zona horaria deseada. Esto es ideal para mostrar la hora a usuarios de diferentes regiones.
Lista de todas las zonas horarias
\n\nSi no sabes qué zona horaria especificar, puedes obtener la lista completa:
\n\nconsole.log(Intl.supportedValuesOf('timeZone'));\n// ["Africa/Abidjan", "Africa/Accra", ..., "Pacific/Wallis"]\n\nEsta lista incluye más de 500 zonas horarias. Úsala para asegurarte de que tu zona horaria sea compatible.
\n\nMoment.js: un clásico, pero con reservas
\n\nDurante mucho tiempo, moment.js fue el estándar para trabajar con fechas en JavaScript. Sabe analizar, formatear, manipular fechas y, por supuesto, trabajar con zonas horarias a través del plugin moment-timezone.
Instalación
\n\nnpm install moment moment-timezone\n\nEjemplo con zonas horarias
\n\nconst moment = require('moment-timezone');\n\nconst now = moment();\nconsole.log(now.tz('Europe/Moscow').format('YYYY-MM-DD HH:mm'));\n// 2025-03-15 14:00 — hora de Moscú\n\nconst nyTime = moment.tz('2025-03-15 12:00', 'America/New_York');\nconsole.log(nyTime.clone().tz('Europe/Moscow').format('YYYY-MM-DD HH:mm'));\n// 2025-03-15 19:00 — diferencia de 7 horas\n\nImportante: moment.js es una librería heredada. Los propios autores recomiendan migrar