Skip to content
Unix timestamps — Segundos, milisegundos, Año 2038 y qué vigilar

Fechas y hora

Unix timestamps — Segundos, milisegundos, Año 2038 y qué vigilar

Los Unix timestamps parecen simples y se rompen de forma sorprendente. Segundos vs milisegundos, el problema del 2038, y las reglas para que la aritmética no se coma tu app.

El tiempo Unix es lo más parecido a un reloj universal que tiene la computación. También es origen de algunos de los bugs más tozudos en pipelines de datos, porque cada lenguaje, BD y API traza la línea en un sitio ligeramente distinto. Esta guía cubre qué es Unix time, las tres trampas que causan la mayoría de bugs, y las reglas para mantener limpia la aritmética de tiempo.

Qué es un Unix timestamp en realidad

Un Unix timestamp es el número de segundos transcurridos desde 1970-01-01 00:00:00 UTC, sin contar leap seconds. Es un escalar. No lleva zona horaria porque siempre es UTC por definición.

0              → 1970-01-01 00:00:00 UTC
1000000000     → 2001-09-09 01:46:40 UTC  (el "Billenium")
1700000000     → 2023-11-14 22:13:20 UTC
2147483647     → 2038-01-19 03:14:07 UTC  (máx int 32-bit firmado)

Al ser un escalar en UTC, dos timestamps se comparan con <, se restan para obtener duración, y se guardan en cualquier columna entera sin anotación de zona. Ahí está todo el atractivo.

Para conversión interactiva entre timestamps y fechas legibles, el timestamp converter es lo más rápido; para renderizar un instante UTC en una zona concreta, el timezone converter hace esa conversión.

Segundos vs milisegundos — el problema de unidades

Stacks distintos tienen defaults distintos. Es el bug más común con Unix timestamps.

UnidadDígitos (hoy)Suele vivir en
Segundos10Unix date +%s, Python time.time() (truncado), epoch Postgres, kernel Linux
Milisegundos13JavaScript Date.now(), Java System.currentTimeMillis(), la mayoría de APIs móviles
Microsegundos16Python datetime.timestamp() * 1_000_000, Go time.UnixMicro
Nanosegundos19Go time.UnixNano, Linux clock_gettime(CLOCK_REALTIME)

Truco de detección rápido: un timestamp de “ahora” está sobre 1.76e9 en segundos. Si tu valor es cuatro órdenes de magnitud mayor, está en milisegundos. Tres más, microsegundos. Seis más, nanosegundos.

// Detectar unidades por magnitud
function detectUnit(ts) {
  if (ts < 1e11) return "seconds";        // ~año 5138
  if (ts < 1e14) return "milliseconds";   // ~año 5138
  if (ts < 1e17) return "microseconds";
  return "nanoseconds";
}

// Normaliza cualquier cosa a milisegundos
function toMillis(ts) {
  if (ts < 1e11) return ts * 1000;
  if (ts < 1e14) return ts;
  if (ts < 1e17) return Math.floor(ts / 1000);
  return Math.floor(ts / 1_000_000);
}

Elige una unidad por API y documéntala. Si construyes una API pública, los números JSON solo garantizan precisión de entero hasta 2^53 - 1, así que los nanosegundos en JSON deberían ser strings, no números.

El problema del Año 2038

Un entero 32-bit firmado tope en 2.147.483.647. Interpretado como segundos desde 1970, eso es 2038-01-19 03:14:07 UTC. Un segundo después, un time_t de 32 bits ingenuo envuelve a -2.147.483.648, que es 1901-12-13 20:45:52 UTC.

Fue el equivalente Y2K del mundo Unix. En la mayoría de sistemas modernos ya está arreglado:

  • Los sistemas operativos 64-bit usan time_t de 64 bits desde aproximadamente mediados de los 2000 para userland Linux, 2017 para Windows.
  • Los sistemas Linux 32-bit obtuvieron time_t de 64 bits en glibc 2.34 (2021) y kernel 5.6+ para nuevas syscalls.
  • Los sistemas embebidos son el riesgo restante. Controladores industriales, routers antiguos, dispositivos IoT con vida de 20 años seguirán fallando en 2038.

Dos consecuencias prácticas hoy:

  1. No diseñes sistemas nuevos alrededor de time_t de 32 bits. Usa enteros 64-bit, o milisegundos, o strings ISO 8601.
  2. Si importas datos de sistemas antiguos, chequea timestamps cerca de 2147483647. Un valor truncado o envuelto es la pista.

UTC vs hora local — no seas listo

La regla dura: guarda timestamps como enteros UTC. Renderízalos en la zona local del usuario al mostrar. Nunca guardes hora local. Nunca guardes “hora local más offset” salvo que construyas una app de calendario (y aún así, piénsatelo).

La versión de diez mil palabras de esta regla vive en la guía de manejo de timezones — es la regla más violada en backend.

Corolario rápido: cuando loggees un evento, logguea su Unix timestamp UTC. No 2026-04-17 14:33:11 en alguna zona local, que es ambiguo dos veces al año en transiciones DST.

Leap seconds y por qué la mayoría de apps los ignoran

El tiempo Unix, por definición explícita, no cuenta leap seconds. Un leap second insertado a las 23:59:60 UTC en 31 de diciembre repite el mismo Unix timestamp dos veces, o (según la estrategia de reloj del servidor) el reloj se desliza 1 segundo en una ventana alrededor de medianoche.

Para la mayoría de apps, la respuesta correcta es “no me importa”. Las duraciones menores de un día no se ven afectadas; las mayores han acumulado quizá 27 leap seconds totales desde 1972 (todos positivos), error de redondeo para la mayor parte de la lógica de negocio.

Donde sí importa:

  • Sistemas financieros con orden regulatorio de timestamps.
  • Experimentos físicos y astronomía.
  • Protocolos de red con sincronización sub-segundo.

Si has visto un log con 23:59:60, es un leap second. El International Earth Rotation Service anunció en 2022 que el último leap second se insertará como muy tarde en 2035.

Ordenación, monotonicidad y “ahora”

Tres puntos sutiles:

  1. Los relojes del sistema pueden ir hacia atrás. NTP desliza y salta. Los contenedores pausan y resumen. Un timestamp que acabas de escribir puede ser “anterior” al escrito hace cinco minutos. Si necesitas IDs estrictamente monotónicos, usa un contador (o un UUID v7 — mira la pieza UUID v4 vs v7), no un timestamp.
  2. “Ahora” no es un valor único. Entre const a = Date.now() y const b = Date.now() el tiempo se movió. Si haces debounce o rate-limiting, calcula “ahora” una vez y reutiliza.
  3. Comparar timestamps de relojes distintos no es seguro. Los sistemas distribuidos no tienen reloj global. Si el cliente manda su timestamp y el servidor tiene el suyo, no los restes tratando el resultado como duración real.

Convenciones de formato que sobreviven

Al serializar un timestamp a texto, tienes dos opciones razonables:

  • Un entero en una unidad documentada (segundos o milisegundos), anotada en el nombre del campo: created_at_ms.
  • Un string ISO 8601: 2026-04-17T14:33:11Z. La Z (o +00:00) es obligatoria; un 2026-04-17T14:33:11 a secas es una hora sin zona y es ambiguo.

Cualquier otra cosa — 14/04/2026, April 17, 2026 2:33 PM, Unix seconds sin unidad en el nombre — es un bug futuro.

# Unix seconds ahora
date +%s
# 1776556391

# ISO 8601 UTC ahora
date -u +%Y-%m-%dT%H:%M:%SZ
# 2026-04-17T14:33:11Z

# Convertir Unix timestamp a ISO local
date -d @1776556391
# Fri Apr 17 16:33:11 CEST 2026

Conclusiones

Los Unix timestamps son segundos UTC (o ms, micros, nanos — chequea tu stack). Detecta la unidad por magnitud, normaliza en el borde, documenta en el nombre del campo. El Año 2038 está casi resuelto en sistemas 64-bit pero real en embebidos. Los leap seconds se pueden ignorar tranquilamente en casi toda app. Nunca guardes hora local. Para conversión interactiva usa el timestamp converter; para display por zona, el timezone converter. Para la filosofía completa de zonas, lee la guía de timezones en backend.

Herramientas relacionadas

Por ·