Las marcas de tiempo Unix son uno de los formatos de datos más importantes en la programación — aparecen en registros de bases de datos, respuestas de APIs, archivos de registro, metadatos del sistema de archivos, tokens de autenticación e innumerables otros lugares. El formato es elegantemente simple: un solo entero que representa los segundos (o milisegundos, microsegundos o nanosegundos) desde el 1 de enero de 1970. Sin embargo, trabajar con marcas de tiempo correctamente es sorprendentemente complicado debido al manejo de zonas horarias, los desajustes de precisión entre sistemas y los casos límite del horario de verano. Las secciones siguientes explican qué es el tiempo Unix y por qué existe, cómo manejar correctamente las zonas horarias al convertir, y los errores comunes que atrapan a los desarrolladores incluso después de años de experiencia.
Qué Es el Tiempo Unix y Por Qué Existe
El tiempo Unix, también llamado tiempo Epoch o tiempo POSIX, es el número de segundos transcurridos desde el 1 de enero de 1970 00:00:00 UTC — un punto de referencia llamado el epoch Unix. Los valores negativos representan fechas anteriores a ese epoch, los positivos representan fechas posteriores. El formato se originó a principios de la década de 1970, cuando los sistemas Unix necesitaban una forma compacta e independiente de la zona horaria para almacenar marcas de tiempo en los metadatos del sistema de archivos y los registros. Un solo entero con signo de 32 bits podía representar fechas de 1901 a 2038, lo que parecía suficiente en el momento del diseño pero crea el famoso Problema del Año 2038 a medida que ese rango expira. Los sistemas modernos usan enteros de 64 bits, lo que empuja la expiración hasta el año 292 mil millones. La elegancia del tiempo Unix es que no tiene zona horaria, ni horario de verano, ni segundos intercalares (oficialmente — la mayoría de las implementaciones simplemente reparten los raros segundos intercalares), ni complejidad de calendario. Es un contador que aumenta de forma monótona y que identifica de manera inequívoca un momento específico. Las zonas horarias, las fechas de calendario y los formatos legibles para humanos se superponen al momento de la visualización. Esto hace del tiempo Unix el formato preferido para comparaciones (`if (tokenExpiresAt < now)`), ordenamiento y almacenamiento de marcas de tiempo en bases de datos de sistemas distribuidos que abarcan distintas zonas horarias. Los formatos legibles como `2024-04-21 11:58:41` se derivan del valor Unix almacenado solo al mostrarlo a un usuario.
Manejo de Zonas Horarias — La Parte Sutil
Una marca de tiempo Unix en sí misma no tiene zona horaria — representa un momento específico en tiempo absoluto. Cuando la conviertes a una forma legible, eliges una zona horaria para la visualización, y la misma marca de tiempo produce distintas horas locales en distintas zonas. Por ejemplo, 1713711521 segundos después del epoch son las 15:58:41 UTC, pero ese mismo momento son las 11:58:41 EDT (America/New_York, UTC-4), las 08:58:41 PDT (America/Los_Angeles, UTC-7), las 00:58:41 JST del día siguiente (Asia/Tokyo, UTC+9) e innumerables otras horas locales por todo el mundo. Lograr esto correctamente en la práctica requiere nombres de zona horaria IANA como `America/New_York` en lugar de desfases fijos como `UTC-05:00`, porque los nombres IANA codifican el historial completo del horario de verano. Decir "4 PM EST el 15 de julio de 2024" es en realidad ambiguo porque la hora del este observa el horario de verano y las fechas de julio están en EDT (UTC-4), no en EST (UTC-5). Las zonas horarias IANA resuelven esta ambigüedad automáticamente — la API Intl del navegador y las bibliotecas del lado del servidor como pytz, moment-timezone y ZoneId de Java usan la base de datos IANA y manejan correctamente las transiciones históricas del horario de verano. Este conversor usa el Intl.DateTimeFormat integrado del navegador con soporte completo de zonas horarias IANA, lo que significa que produce horas locales correctas para cualquier zona válida, incluyendo fechas históricas que se remontan a 1970 o antes.
Los Errores Comunes que Atrapan Incluso a Desarrolladores Experimentados
Un puñado de errores de marcas de tiempo aparecen tan a menudo que vale la pena interiorizarlos como una lista de verificación. Primero, la confusión entre segundos y milisegundos: el objeto Date de JavaScript trabaja en milisegundos mientras que time.time() de Python trabaja en segundos, y mezclarlos accidentalmente multiplica o divide tus fechas por 1000. Revisa la magnitud: los números de 10 dígitos son segundos, los de 13 dígitos son milisegundos, los de 16 dígitos son microsegundos. Segundo, la suposición de zona horaria al analizar: la cadena "2024-04-21 11:58:41" no tiene zona horaria, y distintos analizadores usan suposiciones predeterminadas diferentes. El constructor Date de JavaScript la trata como hora local; el datetime.fromisoformat de Python la trata como ingenua (sin zona horaria). Siempre adjunta una zona horaria explícita a las cadenas ambiguas antes de analizarlas. Tercero, los casos límite del horario de verano en las transiciones de primavera y otoño: las 2:30 AM del día en que se adelanta el reloj no existen en la mayoría de las zonas horarias de EE. UU. (el reloj salta de la 1:59 a las 3:00), y la 1:30 AM del día en que se retrasa el reloj existe dos veces. La aritmética de fechas que suma o resta horas a través de un límite del horario de verano puede producir resultados sorprendentes a menos que uses bibliotecas que consideran IANA. Cuarto, la deriva del "ahora" entre servidores: los relojes de los servidores se desvían por milisegundos o segundos, así que los tokens generados en un servidor y validados en otro necesitan una ventana de tolerancia. Quinto, los segundos intercalares: rara vez relevantes en la práctica porque la mayoría de los sistemas los reparten, pero críticos para aplicaciones científicas o financieras precisas. Este conversor evita la mayoría de estos al usar las bien probadas APIs Intl del navegador, pero los conceptos subyacentes siguen importando al escribir código que consume los valores convertidos.