Mostrar tiempo legible para humanos en el navegador
Tu servidor almacena marcas de tiempo en UTC. Tus usuarios viven en docenas de zonas horarias. La brecha entre estas dos realidades—cadenas ISO en bruto versus “hace 2 horas”—determina si tu interfaz se siente nativa o extraña.
Los navegadores modernos ahora manejan tiempo legible para humanos en JavaScript sin bibliotecas de terceros. Este artículo cubre las APIs nativas que deberías usar: Intl.DateTimeFormat, Intl.RelativeTimeFormat, Intl.DurationFormat, y la API Temporal para lógica consciente de zonas horarias.
Puntos clave
- Usa
Intl.DateTimeFormatpara marcas de tiempo absolutas adaptadas a la configuración regional, pasando identificadores de zona horaria IANA directamente para evitar cálculos manuales de desplazamiento. - Usa
Intl.RelativeTimeFormatcon una pequeña función auxiliar para producir frases naturales como “ayer” o “hace 3 horas”. - Usa
Intl.DurationFormatpara tiempo transcurrido y cuentas regresivas, pero verifica la compatibilidad del navegador ya que la disponibilidad base llegó solo en 2025. - La API Temporal reemplaza el objeto
Datepropenso a errores con tipos explícitos e inmutables—adóptala para proyectos nuevos mientras dependes de los formateadores Intl para bases de código existentes.
Marcas de tiempo absolutas con Intl.DateTimeFormat
Cuando los usuarios necesitan fechas y horas exactas, Intl.DateTimeFormat maneja la localización automáticamente. Respeta la configuración regional del usuario y formatea las fechas según las convenciones regionales.
const date = new Date('2026-03-15T14:30:00Z')
const formatter = new Intl.DateTimeFormat('en-US', {
dateStyle: 'medium',
timeStyle: 'short',
timeZone: 'America/New_York'
})
console.log(formatter.format(date)) // "Mar 15, 2026, 10:30 AM"
La API acepta identificadores de zona horaria IANA directamente, eliminando los cálculos manuales de desplazamiento. Para formateo local del usuario, detecta la zona horaria automáticamente:
const userTimezone = Intl.DateTimeFormat().resolvedOptions().timeZone
Esto devuelve valores como "Europe/London" o "Asia/Tokyo", que puedes pasar directamente a los formateadores.
Tiempo relativo con Intl.RelativeTimeFormat
Los feeds sociales, notificaciones y registros de actividad se benefician de marcas de tiempo relativas. Intl.RelativeTimeFormat produce frases como “hace 3 días” o “en 2 horas” con localización adecuada.
const rtf = new Intl.RelativeTimeFormat('en', { numeric: 'auto' })
rtf.format(-1, 'day') // "yesterday"
rtf.format(-3, 'hour') // "3 hours ago"
rtf.format(2, 'week') // "in 2 weeks"
La opción numeric: 'auto' produce lenguaje natural (“yesterday”) en lugar de números literales (“1 day ago”) cuando es apropiado.
Necesitas calcular la diferencia tú mismo—la API formatea valores, no fechas. Una función auxiliar simple funciona:
function getRelativeTime(date) {
const now = Date.now()
const diffInSeconds = Math.round((date - now) / 1000)
const units = [
{ unit: 'year', seconds: 31536000 },
{ unit: 'month', seconds: 2592000 },
{ unit: 'day', seconds: 86400 },
{ unit: 'hour', seconds: 3600 },
{ unit: 'minute', seconds: 60 },
{ unit: 'second', seconds: 1 }
]
for (const { unit, seconds } of units) {
if (Math.abs(diffInSeconds) >= seconds) {
const value = Math.round(diffInSeconds / seconds)
return new Intl.RelativeTimeFormat('en', { numeric: 'auto' })
.format(value, unit)
}
}
return 'just now'
}
Los valores de mes y año anteriores usan aproximaciones de segundos fijas. Para diferencias precisas de calendario a través de longitudes de mes variables o años bisiestos, usa Temporal o una biblioteca de fechas dedicada en lugar de constantes de segundos fijas.
Ten en cuenta que Math.round ocasionalmente puede empujar un valor a la siguiente unidad (por ejemplo, 89 segundos se redondea a 1 cuando se divide por 60, produciendo “1 minute ago” en lugar de “89 seconds ago”). Si necesitas límites más estrictos, usa Math.trunc en su lugar.
Discover how at OpenReplay.com.
Formateo de duración con Intl.DurationFormat
Para tiempo transcurrido, cuentas regresivas o duraciones de video, Intl.DurationFormat proporciona salida consistente a través de configuraciones regionales:
const duration = { hours: 2, minutes: 45, seconds: 30 }
const df = new Intl.DurationFormat('en', { style: 'long' })
console.log(df.format(duration)) // "2 hours, 45 minutes, 30 seconds"
const dfShort = new Intl.DurationFormat('en', { style: 'digital' })
console.log(dfShort.format(duration)) // "2:45:30"
Esta API alcanzó soporte base entre motores en 2025 y está disponible en navegadores modernos, aunque aún deberías confirmar la compatibilidad con tu matriz de soporte específica.
La API Temporal para manejo más seguro de fechas
La API Temporal aborda problemas de larga data con el objeto Date de JavaScript—mutabilidad, confusión de zonas horarias e inconsistencias de análisis. Temporal es compatible con versiones modernas de Chromium y Firefox desde 2026, pero la detección de características sigue siendo esencial porque el soporte aún no es universal en todos los navegadores.
if (typeof Temporal !== 'undefined') {
const now = Temporal.Now.zonedDateTimeISO('America/Los_Angeles')
console.log(now.toString())
}
Temporal proporciona tipos distintos para diferentes conceptos: Temporal.PlainDate para fechas de calendario, Temporal.PlainTime para hora de reloj de pared, y Temporal.ZonedDateTime para momentos conscientes de zona horaria. Esta explicitud previene los errores que plagan el código basado en Date.
Para proyectos nuevos, Temporal ofrece la base más limpia. Para bases de código existentes, los formateadores Intl funcionan perfectamente con objetos Date heredados.
Recomendaciones prácticas
Almacena marcas de tiempo como cadenas ISO 8601 en UTC. Formatéalas del lado del cliente usando las APIs Intl. Evita analizar cadenas de fecha no ISO—se comportan de manera inconsistente entre navegadores.
Reutiliza instancias de formateador cuando formatees múltiples marcas de tiempo. Crear un formateador una vez y llamar a format() repetidamente es significativamente más rápido que recrear uno en cada llamada.
Usa HTML semántico para accesibilidad:
<time datetime="2026-03-15T14:30:00Z">March 15, 2026</time>
Conclusión
La plataforma nativa ahora maneja lo que antes requería Moment.js o bibliotecas similares. Intl.DateTimeFormat cubre marcas de tiempo absolutas, Intl.RelativeTimeFormat cubre frases relativas, Intl.DurationFormat cubre tiempo transcurrido, y la API Temporal proporciona una base sólida para lógica de fechas consciente de zonas horarias. Para tiempo legible para humanos en el navegador, estas herramientas integradas son todo lo que necesitas.
Preguntas frecuentes
No. La API solo formatea un valor numérico y una unidad en una cadena localizada. Debes calcular la diferencia entre dos fechas tú mismo y elegir la unidad apropiada antes de pasarlas al método format. La función auxiliar mostrada en este artículo es un patrón común para ese cálculo.
Temporal está disponible en versiones modernas de Chromium y Firefox desde 2026, pero aún no es universalmente compatible en todos los navegadores. Siempre usa detección de características antes de llamar métodos Temporal, y considera un polyfill si necesitas compatibilidad amplia. Solo para formateo, las APIs Intl ya tienen amplio soporte y funcionan bien con el objeto Date heredado.
Construir un formateador Intl implica resolver datos de configuración regional, reglas de zona horaria y opciones de formateo, lo cual conlleva un costo medible. Crear una instancia y llamar a su método format repetidamente es significativamente más rápido que reconstruir el formateador en cada invocación, especialmente al renderizar listas largas de marcas de tiempo.
Por defecto, sí. Si omites la opción timeZone, el formateador usa la zona horaria del entorno de ejecución, que en un navegador coincide con la configuración del sistema del usuario. Puedes recuperar este valor explícitamente mediante Intl.DateTimeFormat().resolvedOptions().timeZone y pasarlo a otros formateadores o enviarlo a tu servidor.
Complete picture for complete understanding
Capture every clue your frontend is leaving so you can instantly get to the root cause of any issue with OpenReplay — the open-source session replay tool for developers. Self-host it in minutes, and have complete control over your customer data.
Check our GitHub repo and join the thousands of developers in our community.