Saltar al contenido
LeedyBox
Apoyar

Marcas de tiempo Unix explicadas

Una marca de tiempo Unix es un único número que representa un instante. Es fácil de guardar y comparar, pero las unidades, las zonas horarias y los formatos de texto provocan muchos errores de conversión.

Qué es el tiempo Unix

El tiempo Unix (también llamado tiempo epoch o tiempo POSIX) cuenta los segundos transcurridos desde 1970-01-01 00:00:00 UTC, la época Unix (epoch). 0 es la propia época, 1700000000 corresponde a 2023-11-14 22:13:20 UTC y los valores negativos son instantes anteriores a 1970: -1 es 1969-12-31 23:59:59 UTC.

El número no contiene ninguna zona horaria: describe el mismo instante en todas partes, lo que lo hace práctico para guardar, ordenar y comparar eventos.

El tiempo Unix ignora los segundos intercalares: todos los días tienen exactamente 86.400 segundos. Cuando se añade un segundo intercalar a UTC, los sistemas repiten un segundo o lo reparten a lo largo de un periodo más largo («smearing»), así que una diferencia que abarca un segundo intercalar es un segundo más corta que el tiempo que ha transcurrido físicamente.

¿Segundos, milisegundos, microsegundos o nanosegundos?

Muchos sistemas cuentan en unidades más pequeñas, y el número no indica cuál. El mismo instante puede aparecer como cuatro números muy distintos:

Unidad2023-11-14 22:13:20 UTCDígitos (2001–2286)Habitual en
Segundos170000000010date +%s, muchas API, claims exp de JWT
Milisegundos170000000000013Date.now() de JavaScript, System.currentTimeMillis() de Java
Microsegundos170000000000000016Algunas bases de datos y sistemas de registro
Nanosegundos170000000000000000019UnixNano() de Go, time.time_ns() de Python

Contar los dígitos es la comprobación más rápida para fechas actuales. El conversor de LeedyBox usa la misma idea: los valores de hasta 1011 se interpretan como segundos; hasta 1014, como milisegundos; hasta 1017, como microsegundos, y los valores mayores, como nanosegundos. Esta regla práctica falla con fechas muy alejadas de hoy, así que comprueba la unidad cuando un resultado parezca extraño.

La precisión también importa. Los números de JavaScript solo representan enteros con exactitud hasta 253 (unos 9 × 1015), así que un valor en nanosegundos como 1700000000123456789 pierde sus últimos dígitos cuando se interpreta como un número normal. Guarda esos valores como cadenas o usa BigInt; el conversor lo hace internamente. Para leer el claim exp de un token, decodifícalo con la herramienta Base64 / URL / JWT.

Zonas horarias y horario de verano

Para mostrar una marca de tiempo como fecha y hora, necesitas una zona horaria. UTC es la referencia; la hora local añade un desfase, como +09:00 en Seúl o −05:00 en Nueva York en invierno.

Es preferible usar nombres de zona horaria IANA, como Asia/Seoul o America/New_York, en lugar de desfases fijos y abreviaturas: un nombre incluye la historia de la zona y sus reglas de horario de verano, mientras que una abreviatura como CST designa varias zonas. Las reglas proceden de la base de datos de zonas horarias, que cambia varias veces al año, y los navegadores, los sistemas operativos y los lenguajes incluyen sus propias copias, así que los resultados para fechas pasadas o futuras pueden variar.

El horario de verano crea dos casos problemáticos al convertir una hora local en una marca de tiempo:

  • Hueco: cuando se adelantan los relojes, algunas horas locales no existen. En America/New_York, 2026-03-08 02:30 se omite porque los relojes pasan directamente de las 02:00 a las 03:00.
  • Solapamiento: cuando se atrasan los relojes, algunas horas locales se dan dos veces. 2026-11-01 01:30 ocurre una vez en EDT (UTC−04:00) y otra vez una hora después en EST (UTC−05:00).

Las bibliotecas resuelven estos casos de forma distinta. El conversor de LeedyBox usa la hora válida posterior en un hueco (aquí, las 03:30) y la primera aparición en un solapamiento, y lo explica en una nota. Las tareas programadas se enfrentan al mismo problema; consulta Cómo leer expresiones cron.

ISO 8601, RFC 3339 y fechas HTTP

Cuando un instante tiene que ser legible, escríbelo en ISO 8601 o en su perfil más estricto para internet, RFC 3339:

2023-11-14T22:13:20Z
2023-11-15T07:13:20+09:00
2023-11-14T22:13:20.500Z

Z significa UTC. Con Z o con un desfase, la cadena no es ambigua. Una cadena sin ninguno de los dos, como 2023-11-14T22:13:20, es una hora local en una zona desconocida, y los analizadores no coinciden en cómo interpretarla.

Las cabeceras HTTP como Last-Modified y Expires usan un formato más antiguo derivado del formato de fecha del correo electrónico (RFC 2822, ahora RFC 5322), escrito en GMT: Tue, 14 Nov 2023 22:13:20 GMT.

El problema del año 2038

Muchos sistemas antiguos guardan el tiempo Unix en un entero de 32 bits con signo. Su valor máximo, 2147483647, corresponde a 2038-01-19 03:14:07 UTC. Un segundo después, el contador se desborda a -2147483648, que se interpreta como 1901-12-13 20:45:52 UTC. Los sistemas operativos y lenguajes actuales usan sobre todo valores de tiempo de 64 bits, que abarcan cientos de miles de millones de años, pero los campos de 32 bits siguen apareciendo en dispositivos integrados, formatos de archivo, columnas de bases de datos y protocolos de red. Si tu código o tus datos guardan segundos en 32 bits, planifica el cambio con antelación y prueba ya fechas posteriores a 2038.

Marcas de tiempo en código y bases de datos

JavaScript trabaja en milisegundos:

Math.floor(Date.now() / 1000);                  // hora Unix actual en segundos
new Date(1700000000 * 1000).toISOString();      // "2023-11-14T22:13:20.000Z"
Date.parse("2026-10-03T09:00:00+09:00") / 1000; // 1790985600

time.time() de Python devuelve los segundos como número de coma flotante. Pasa tz=timezone.utc; de lo contrario, fromtimestamp() devuelve la hora local del equipo sin zona horaria:

import time
from datetime import datetime, timezone

int(time.time())                                     # segundos
datetime.fromtimestamp(1700000000, tz=timezone.utc)  # 2023-11-14 22:13:20+00:00
datetime.fromisoformat("2026-10-03T09:00:00+09:00").timestamp()  # 1790985600.0

En SQL, las funciones varían según la base de datos:

-- PostgreSQL
SELECT extract(epoch FROM now());   -- segundos, con fracción
SELECT to_timestamp(1700000000);    -- timestamp with time zone
-- MySQL
SELECT UNIX_TIMESTAMP();
SELECT FROM_UNIXTIME(1700000000);   -- en la zona horaria de la sesión

Para el almacenamiento, unos pocos hábitos evitan la mayoría de los problemas:

  • Guarda en UTC los instantes que ya han ocurrido, ya sea en una columna de tipo timestamp con zona horaria o como un entero de 64 bits cuya unidad forme parte del nombre de la columna, como created_at_ms.
  • Guarda los eventos locales futuros, como una reunión a las 09:00 en Seúl, como la fecha y la hora locales más el nombre de zona IANA, y calcula la marca de tiempo cuando la necesites, para que un cambio posterior de las reglas no mueva la reunión.
  • No mezcles unidades en una misma columna; una unidad equivocada desvía el valor en un factor de 1000 o más.

Preguntas frecuentes

¿Por qué mi marca de tiempo se convierte en una fecha de 1970?

Probablemente el valor se leyó en la unidad equivocada: los segundos leídos como milisegundos caen en enero de 1970, y los milisegundos leídos como segundos caen decenas de miles de años en el futuro. Cuenta los dígitos o elige la unidad en el conversor.

¿Una marca de tiempo Unix depende de mi zona horaria?

No. Cuenta los segundos desde un instante fijo en UTC. Solo la fecha y la hora con que se muestra dependen de la zona horaria.

¿Puede el tiempo Unix representar un segundo intercalar?

No. El tiempo Unix trata cada día como 86.400 segundos, así que una hora UTC como 23:59:60 no tiene marca de tiempo propia.