Herramientas para desarrolladores·6 min

Entendiendo los timestamps Unix: Una guía para desarrolladores

Qué son los timestamps Unix, cómo funcionan, segundos intercalares, el problema de 2038 y conversión práctica.

Por qué los desarrolladores deben entender los timestamps Unix

Un timestamp Unix es un entero que representa el número de segundos transcurridos desde 00:00:00 UTC del 1 de enero de 1970 (la época Unix). Son la lengua franca del tiempo en la informática: las bases de datos los indexan, las APIs los devuelven, los sistemas de archivos los almacenan, y protocolos como NTP y HTTP los usan. Todo desarrollador eventualmente tiene que convertir entre timestamps Unix y fechas legibles por humanos — y depurar los problemas que surgen cuando diferentes sistemas representan el tiempo de manera diferente.

Esta guía cubre qué son los timestamps Unix, cómo funcionan en diferentes lenguajes, las complicaciones de zonas horarias y segundos intercalares, y el próximo problema de 2038.

Cómo funcionan los timestamps Unix

Un timestamp Unix es solo un conteo entero de segundos. No hay zona horaria, no hay horario de verano, no hay aritmética de calendario. Sumar 86,400 a un timestamp siempre avanza la fecha exactamente un día en UTC.

``` 0 = 1970-01-01 00:00:00 UTC (la época) 1,000 = 1970-01-01 00:16:40 UTC 1,000,000 = 1970-01-12 13:46:40 UTC 1,000,000,000 = 2001-09-09 01:46:40 UTC (el "billonio") 1,500,000,000 = 2017-07-14 02:40:00 UTC 2,000,000,000 = 2033-05-18 03:33:20 UTC 2,147,483,647 = 2038-01-19 03:14:07 UTC (máx. 32 bits con signo) ```

El valor máximo representable depende del tipo de entero:

  • 32 bits con signo: 2.147.483.647 (2^31 − 1) → 2038-01-19 03:14:07 UTC
  • 32 bits sin signo: 4.294.967.295 (2^32 − 1) → 2106-02-07 06:28:15 UTC
  • 64 bits con signo: 9.223.372.036.854.775.807 → año 292.277.026.596

Por eso existe el problema de 2038: cualquier timestamp con signo de 32 bits se desborda el 2038-01-19. Los timestamps de 64 bits evitan el problema durante cientos de miles de millones de años.

Tiempo Unix vs UTC: el problema del segundo intercalar

Estrictamente, el tiempo Unix ignora los segundos intercalares. Cuenta cada segundo como si hubiera exactamente 86.400 por día, incluso cuando las autoridades internacionales de tiempo añaden un segundo intercalar a UTC. Después de que se hayan insertado 27 segundos intercalares (a fecha de 2024), el tiempo Unix está ahora unos 27 segundos por delante del UTC "verdadero".

En la práctica, esto rara vez importa. TAI (Tiempo Atómico Internacional) mantiene segundos perfectos, y UTC se mantiene dentro de 0,9 segundos de UT1 (tiempo de rotación de la Tierra) añadiendo segundos intercalares. El tiempo Unix simplemente usa el conteo de segundos de TAI menos un desplazamiento fijo.

Si necesitas tiempo atómico estricto, usa TAI directamente. Para todo lo demás, la pequeña deriva del tiempo Unix es irrelevante.

Zonas horarias y desplazamientos

Un timestamp Unix se refiere a un único instante en el tiempo. Para mostrarlo en forma legible por humanos, aplicas un desplazamiento de zona horaria. Desplazamientos comunes:

| Zona | Abreviatura | Desplazamiento desde UTC | |------|-------------|--------------------------| | Tiempo Universal Coordinado | UTC | 0 | | Este de EE. UU. (invierno) | EST | −5 | | Este de EE. UU. (verano) | EDT | −4 | | Pacífico de EE. UU. (invierno) | PST | −8 | | Pacífico de EE. UU. (verano) | PDT | −7 | | Reino Unido (invierno) | GMT | 0 | | Reino Unido (verano) | BST | +1 | | Europa Central (invierno) | CET | +1 | | Europa Central (verano) | CEST | +2 | | Japón | JST | +9 | | China | CST | +8 | | India | IST | +5:30 | | Australia (Sídney, invierno) | AEST | +10 | | Australia (Sídney, verano) | AEDT | +11 |

Observa que India y China usan un único desplazamiento durante todo el año (sin horario de verano). EE. UU., Reino Unido y la mayor parte de Europa observan DST, lo que complica todo.

Un error común: un servidor almacena un timestamp Unix (siempre UTC), luego lo muestra sin aplicar el desplazamiento local del usuario, y el usuario ve una hora desplazada varias horas. Almacena siempre en UTC, convierte a local en el momento de mostrar.

El problema de 2038 en detalle

El problema de 2038 (también Y2K38) es el desbordamiento de entero con signo de 32 bits que ocurrirá el 2038-01-19 03:14:07 UTC. El siguiente segundo se desborda a −2.147.483.648, que en la mayoría de los sistemas se interpreta como 1901-12-13 20:45:52 UTC. Cualquier cosa que dependa de timestamps Unix como enteros con signo de 32 bits se romperá:

  • Sistemas de archivos que almacenan mtime en time_t de 32 bits
  • Bases de datos antiguas (MySQL antiguo, algunas builds de SQLite)
  • Sistemas embebidos (routers, dispositivos IoT, coches)
  • Protocolos de red que usan campos de tiempo de 32 bits (NTP, DNS, Kerberos, algunos handshakes TLS)

Los sistemas modernos (Linux de 64 bits, macOS de 64 bits, Windows moderno, bases de datos modernas) ya han migrado a 64 bits. El riesgo está en código heredado y embebido que no se ha actualizado.

La solución: cambiar el tipo de dato de `time_t` (32 bits) a `int64_t` (o equivalente). Un cambio de declaración, más una recompilación. El reto es encontrar cada lugar donde vive la suposición de 32 bits — formatos de archivo, protocolos de red, datos persistidos, bibliotecas de terceros.

Trabajando con timestamps Unix en código

Python

El módulo `datetime` de Python es la herramienta canónica.

```python import datetime from zoneinfo import ZoneInfo

# Timestamp Unix actual (segundos, float) import time now = time.time() # 1700000000.123

# Convertir timestamp Unix a datetime (UTC) ts = 1700000000 utc = datetime.datetime.fromtimestamp(ts, tz=datetime.timezone.utc) # 2023-11-14 22:13:20+00:00

# Convertir timestamp Unix a datetime (zona específica) ny = datetime.datetime.fromtimestamp(ts, tz=ZoneInfo("America/New_York")) # 2023-11-14 17:13:20-05:00

# Convertir datetime a timestamp Unix d = datetime.datetime(2023, 11, 14, 22, 13, 20, tzinfo=datetime.timezone.utc) ts = int(d.timestamp()) # 1700000000

# Formatear como ISO 8601 print(utc.isoformat()) # 2023-11-14T22:13:20+00:00 ```

Cuidado: `datetime.fromtimestamp(ts)` (sin `tz`) usa la zona horaria local, que rara vez es lo que quieres en un contexto de servidor. Pasa siempre una zona horaria explícita.

JavaScript

JavaScript usa milisegundos, no segundos. `Date.now()` devuelve milisegundos desde la época.

```js // Timestamp Unix actual en milisegundos const now = Date.now(); // p. ej., 1700000000000

// Timestamp Unix actual en segundos const nowSec = Math.floor(Date.now() / 1000);

// Convertir segundos a milisegundos y crear un Date const date = new Date(1700000000 * 1000); // 2023-11-14T22:13:20.000Z

// Convertir milisegundos a segundos const ts = Math.floor(date.getTime() / 1000);

// Mostrar en una zona horaria específica con Intl console.log(date.toLocaleString("en-US", { timeZone: "Asia/Tokyo" })); // 11/15/2023, 7:13:20 AM

// ISO 8601 console.log(date.toISOString()); // 2023-11-14T22:13:20.000Z ```

El mayor escollo de JavaScript: todos los demás lenguajes usan segundos; JavaScript usa milisegundos. Olvidar multiplicar o dividir por 1000 es la fuente de incontables errores "fuera por un factor de 1000".

SQL

La mayoría de bases de datos soportan timestamps Unix nativamente o mediante funciones.

```sql -- MySQL SELECT UNIX_TIMESTAMP(NOW()); -- timestamp actual (segundos) SELECT FROM_UNIXTIME(1700000000); -- 2023-11-14 22:13:20 SELECT FROM_UNIXTIME(1700000000, '%Y-%m-%d %H:%i:%s');

-- PostgreSQL SELECT EXTRACT(EPOCH FROM NOW()); -- timestamp actual (segundos, float) SELECT TO_TIMESTAMP(1700000000); -- 2023-11-14 22:13:20+00

-- SQLite SELECT strftime('%Y-%m-%dT%H:%M:%fZ', 'unixepoch', 1700000000); -- 2023-11-14T22:13:20.000Z ```

`UNIX_TIMESTAMP()` de MySQL devuelve segundos; `EXTRACT(EPOCH FROM ...)` de PostgreSQL devuelve segundos con precisión fraccional. SQLite requiere la receta manual con `strftime`.

Bash

El comando `date` maneja timestamps Unix en todo sistema Unix.

```bash # Timestamp Unix actual date +%s # 1700000000

# Convertir timestamp Unix a una cadena de fecha # Linux (GNU date) date -d @1700000000 # Tue Nov 14 22:13:20 PM UTC 2023

# macOS (BSD date) date -r 1700000000 # Tue Nov 14 22:13:20 UTC 2023

# Convertir una cadena de fecha a timestamp Unix # Linux date -d "2023-11-14 22:13:20 UTC" +%s # macOS date -j -f "%Y-%m-%d %H:%M:%S" "2023-11-14 22:13:20" +%s

# Mostrar en una zona horaria específica TZ="Asia/Tokyo" date -d @1700000000 # Wed Nov 15 07:13:20 JST 2023 ```

Para una referencia rápida: `date +%s` para "ahora como tiempo Unix" es un one-liner que usarás semanalmente.

Almacenar timestamps en bases de datos

Mejores prácticas para almacenamiento en bases de datos:

  1. Almacena como enteros (BIGINT): Los timestamps Unix nativos son baratos de almacenar, fáciles de indexar, simples de comparar.
  2. Usa siempre UTC: Convierte a la zona local solo en el momento de mostrar.
  3. Usa BIGINT, no INT: Un entero con signo de 32 bits se desborda en 2038. Usa siempre 64 bits.
  4. Considera precisión de milisegundos: Para logging de eventos de alta frecuencia (trading, gaming, telemetría), 1 segundo de resolución es demasiado grueso. Almacena como BIGINT milisegundos.
  5. Usa TIMESTAMP WITH TIME ZONE: `timestamptz` de PostgreSQL es el más robusto. `TIMESTAMP` de MySQL tiene el problema de 2038; usa `DATETIME` en su lugar.
  6. Indexa columnas timestamp: Queries como `WHERE created_at > ?` son extremadamente comunes. Un índice BTREE en una columna timestamp las hace rápidas.

Un esquema común:

```sql CREATE TABLE events ( id BIGSERIAL PRIMARY KEY, event_type TEXT NOT NULL, payload JSONB NOT NULL, created_at BIGINT NOT NULL, -- Unix ms INDEX idx_events_created (created_at) ); ```

Trampas comunes

El bug de milisegundos de JavaScript

Los timestamps de JavaScript están en milisegundos; todos los demás lenguajes principales usan segundos. Mezclarlos produce timestamps fuera por un factor de 1000.

```js // Desde un backend Python const python_ts = 1700000000; // segundos const js_date = new Date(python_ts); // 1970-01-20T08:13:20.000Z ← ¡MAL!

// Correcto: multiplicar por 1000 const js_date = new Date(python_ts * 1000); ```

Bugs de visualización de zona horaria

Un timestamp se refiere a un momento en el tiempo, no a una fecha. Si tu servidor registra "2023-11-14 22:13:20" sin indicar UTC o local, el usuario no tiene forma de saber cuál es. Siempre:

  • Almacena como timestamp Unix (inherentemente UTC)
  • Envía a clientes con una zona horaria explícita
  • Convierte a local en el momento de mostrar usando la zona real del usuario

```js // El servidor envía "2023-11-14T22:13:20Z" (Z = UTC) // El cliente lo renderiza en la zona local del usuario const d = new Date("2023-11-14T22:13:20Z"); console.log(d.toLocaleString()); // "11/14/2023, 5:13:20 PM" (en EST) ```

Casos límite de DST

Un día de 24 horas en primavera es en realidad 23 horas (DST salta una hora); un día de 24 horas en otoño es 25 horas. El código que asume "sumar 86,400 para obtener mañana" funciona bien; el código que hace "sumar 24 × 60 × 60" o "mañana a las 2:30 AM" puede fallar en las transiciones de DST.

```python # Este es un día de 23 o 25 horas en zonas con DST d = datetime.datetime(2024, 3, 10, 1, 0, 0, tzinfo=ZoneInfo("America/New_York")) # DST empieza print((d + datetime.timedelta(days=1)).isoformat()) # 2024-03-11T01:00:00-05:00 ← correcto print((d + datetime.timedelta(hours=24)).isoformat()) # 2024-03-11T02:00:00-04:00 ← DST ha saltado, esto es 25 horas después ```

Para scheduling y matemáticas de hora del día, prefiere bibliotecas (Luxon, Arrow, date-fns) que manejen estos casos límite correctamente.

Método 1: Use el conversor de timestamp de UtilBoxx (Recomendado)

Para conversiones rápidas durante el desarrollo, el Conversor de Timestamp de UtilBoxx es una herramienta privada, en el navegador, que convierte entre timestamps Unix y fechas en cualquier zona horaria, soporta tanto segundos como milisegundos, y se ejecuta completamente en el cliente. Sin carga, sin registro, sin logs. Márcalo como favorito para la próxima vez que necesites decodificar un timestamp desconocido de una respuesta de API.

Conclusión

Los timestamps Unix son simples, rápidos y universales — pero el ecosistema que los rodea (zonas horarias, segundos intercalares, el problema de 2038, confusión entre milisegundos y segundos) está lleno de trampas. Todo desarrollador eventualmente choca con cada una de ellas; la única defensa es saber que existen.

Mejores prácticas:

  • Almacena como enteros de 64 bits en UTC
  • Convierte a local en el momento de mostrar con la zona horaria real del usuario
  • Usa una biblioteca de zonas horarias real (Luxon, date-fns-tz, zoneinfo) para matemáticas de tiempo no triviales
  • Audita los timestamps de 32 bits ahora si mantienes código heredado

Los timestamps Unix son uno de los formatos de datos más antiguos aún en uso, y nos sobrevivirán a todos — pero solo si los usamos correctamente.