timestamp unix time date converter

Convertidor de Timestamp Unix: Traduce el Tiempo Epoch a Fechas Legibles

Convierte timestamps Unix a fechas legibles por humanos y viceversa. Una herramienta esencial para desarrolladores que trabajan con tiempo epoch y formatos de fecha.

Introducción

Un Unix timestamp es uno de los conceptos más fundamentales en la informática. Representa un momento específico en el tiempo como un entero simple: el número de segundos transcurridos desde el epoch de Unix (1 de enero de 1970, 00:00:00 UTC). Este formato simple y universal sustenta todo, desde registros de bases de datos y respuestas de API hasta archivos de registro y tareas programadas.

A diferencia de cadenas de fechas legibles por humanos como "9 de abril de 2024", un Unix timestamp no tiene zona horaria, ni configuración regional, ni ambigüedad. El número 1712620800 se refiere exactamente al mismo momento en cualquier parte del mundo. Esa propiedad lo convierte en la lengua franca de las fechas y horas en la ingeniería de software.

Historia del Unix Epoch

El sistema operativo Unix fue desarrollado en Bell Labs a finales de los años 60 y principios de los 70 por Ken Thompson, Dennis Ritchie y colegas. El seguimiento del tiempo fue incorporado al kernel desde el principio, pero la elección exacta de la fecha epoch evolucionó durante el desarrollo temprano.

Algunas de las primeras versiones de Unix usaban el 1 de enero de 1971 como epoch. Otras experimentaron con el 1 de enero de 1969. Finalmente, el 1 de enero de 1970, 00:00:00 UTC fue estandarizado: una fecha "redonda" lo suficientemente cercana a la creación del sistema para que los timestamps de eventos reales fueran enteros positivos pequeños.

La elección de 1970-01-01 es, en esencia, arbitraria. Lo que importa no es la fecha en sí, sino la consistencia de la convención. Como todos los sistemas están de acuerdo en el mismo epoch, los timestamps pueden intercambiarse entre programas, lenguajes y plataformas sin ninguna sobrecarga de conversión.

Esta convención fue formalizada posteriormente en POSIX (la Interfaz Portable del Sistema Operativo), que define un Unix timestamp como el número de segundos no bisiestos desde 1970-01-01T00:00:00Z.

Segundos vs. Milisegundos

No todos los "timestamps" son iguales. La distinción más importante es la unidad:

  • Unix timestamp (POSIX): segundos desde el epoch — ej.: 1712620800
  • JavaScript Date: milisegundos desde el epoch — ej.: 1712620800000
  • Java System.currentTimeMillis(): milisegundos desde el epoch
  • Go time.Now().Unix(): segundos; time.Now().UnixNano() da nanosegundos
  • Python time.time(): segundos en punto flotante

La diferencia de factor 1000 entre segundos y milisegundos es una fuente común de errores. Pasar un timestamp en milisegundos a código que espera segundos produce una fecha en el futuro lejano (año ~56.000); lo contrario produce una fecha en enero de 1970.

La conversión es sencilla:

const unix_ms = unix_s * 1000;
const unix_s  = Math.floor(unix_ms / 1000);

Una regla práctica: si tu timestamp tiene 10 dígitos, probablemente está en segundos. Si tiene 13 dígitos, probablemente está en milisegundos.

Formato ISO 8601 y Variantes

ISO 8601 es el estándar internacional para representar fechas y horas. Define una familia de formatos de cadena sin ambigüedad:

2024-04-09                        # Solo fecha
2024-04-09T12:00:00               # Fecha y hora local (sin info de zona horaria)
2024-04-09T12:00:00Z              # UTC (Z = hora Zulu = UTC+0)
2024-04-09T20:00:00+08:00         # Con desplazamiento UTC (ej.: Asia/Shanghai)
2024-04-09T12:00:00.123Z          # Con milisegundos
2024-04-09T12:00:00.123456789Z    # Con nanosegundos

La T separa las partes de fecha y hora. El sufijo Z (de "Zulu", el código fonético OTAN para UTC) significa que la hora está en UTC. Un desplazamiento como +08:00 significa que la hora local está 8 horas adelante de UTC.

ISO 8601 es el formato recomendado para APIs REST, archivos de registro y cualquier sistema que intercambie datos temporales entre fronteras. Es legible por humanos, ordenable como cadena y sin ambigüedades.

Zonas Horarias y UTC

UTC (Tiempo Universal Coordinado) es el estándar de tiempo principal del mundo. No es una zona horaria en sí misma, sino la línea base desde la cual se definen todas las zonas horarias. UTC+0 es lo mismo que el Tiempo Medio de Greenwich (GMT) durante el invierno.

Las zonas horarias se expresan como desplazamientos de UTC: UTC+5:30 (India), UTC-8 (Hora Estándar del Pacífico de EE.UU.), UTC+9 (Japón). Sin embargo, los desplazamientos brutos no son suficientes para describir completamente una zona horaria, porque los desplazamientos cambian con el Horario de Verano (DST).

La Base de Datos de Zonas Horarias IANA (también llamada base de datos tz o zoneinfo) es la lista autoritativa de todas las zonas horarias del mundo. Usa identificadores como America/New_York, Europe/Berlin, Asia/Tokyo y America/Argentina/Buenos_Aires. Estos identificadores encapsulan no solo el desplazamiento UTC actual sino el registro histórico completo de reglas DST y cambios políticos.

Todos los principales lenguajes de programación y sistemas operativos incluyen la base de datos IANA:

  • JavaScript (Node.js): Intl.DateTimeFormat con identificadores IANA
  • Python: módulo zoneinfo (Python 3.9+) o pytz
  • Java: java.time.ZoneId (ej.: ZoneId.of("America/Bogota"))
  • Go: time.LoadLocation("America/Buenos_Aires")

Nunca uses desplazamientos UTC brutos como +05:30 para representar zonas horarias en la lógica de la aplicación. Usa identificadores IANA en su lugar, porque los desplazamientos cambian estacionalmente.

Complicaciones del Horario de Verano (DST)

El Horario de Verano es la práctica de adelantar los relojes una hora durante los meses de verano para extender la luz del día vespertina. Se observa en la mayor parte de Norteamérica y Europa, y en partes de Sudamérica, Oriente Medio y Oceanía. Muchos países, incluidos Japón, China e India, no observan el DST en absoluto.

El DST introduce dos anomalías clásicas:

Avance de primavera (Spring forward): Los relojes saltan de las 2:00 AM directamente a las 3:00 AM. La ventana de 60 minutos entre las 2:00 y las 3:00 AM nunca existe en la hora local. Si programas un trabajo a las 2:30 AM, se ejecuta a las 3:30 AM o se omite por completo, según el programador.

Retroceso de otoño (Fall back): Los relojes regresan de las 2:00 AM a la 1:00 AM. La ventana de 60 minutos entre la 1:00 y las 2:00 AM ocurre dos veces. Si registras una entrada de registro a "1:45 AM hora local", es ambigua: podría ser de la primera o segunda ocurrencia de esa hora.

Los Unix timestamps son completamente inmunes al DST porque siempre son relativos a UTC. El número 1712620800 siempre se refiere al mismo instante, sin importar dónde estés o qué estación sea.

La regla de oro: siempre almacena y transmite timestamps en UTC. Convierte a hora local solo en la capa de presentación, inmediatamente antes de mostrar al usuario humano.

El Problema del Año 2038

El Problema del Año 2038 (también llamado Y2K38 o el Bug del Milenio de Unix) es una vulnerabilidad de software similar en naturaleza al bug del año 2000.

La causa raíz: muchos sistemas heredados almacenan Unix timestamps como un entero de 32 bits con signo. El valor máximo de un entero de 32 bits con signo es 2.147.483.647. Esto corresponde a:

2038-01-19 03:14:07 UTC

Un segundo después de ese momento, un entero de 32 bits con signo desborda y se envuelve al valor más negativo: -2.147.483.648, que corresponde a 1901-12-13 20:45:52 UTC. Los sistemas que desborden repentinamente creerán que la fecha es 1901.

Sistemas potencialmente afectados:

  • Sistemas embebidos heredados y dispositivos IoT compilados para arquitecturas de 32 bits
  • Esquemas de bases de datos antiguas que usan el tipo TIMESTAMP de MySQL (usaba almacenamiento de 32 bits en versiones anteriores a 8.0)
  • Kernels de Linux de 32 bits (resuelto en el kernel para plataformas de 64 bits)
  • Algunos sistemas de archivos más antiguos que registran tiempos de modificación como enteros de 32 bits

La solución es directa: migrar todo el almacenamiento de timestamps a enteros de 64 bits con signo. Un timestamp de 64 bits puede representar fechas hasta aproximadamente el año 292.277.026.596, mucho más allá de cualquier preocupación práctica. La mayoría de los sistemas modernos de 64 bits ya manejan esto correctamente.

Trabajando con Timestamps en Diferentes Lenguajes

JavaScript

// Tiempo actual
const now = Date.now();                   // milisegundos desde el epoch
const unix = Math.floor(now / 1000);      // convertir a segundos

// Parsear un Unix timestamp
const date = new Date(unix * 1000);
console.log(date.toISOString());          // "2024-04-09T12:00:00.000Z"
console.log(date.toLocaleString("es-ES", { timeZone: "Europe/Madrid" }));

Python

import time
import datetime

# Unix timestamp actual (segundos)
unix = int(time.time())

# Convertir a datetime UTC
dt = datetime.datetime.fromtimestamp(unix, tz=datetime.timezone.utc)
print(dt.isoformat())   # "2024-04-09T12:00:00+00:00"

# Usando zoneinfo para zona horaria IANA
from zoneinfo import ZoneInfo
dt_local = dt.astimezone(ZoneInfo("America/Bogota"))
print(dt_local.isoformat())

Go

package main

import (
    "fmt"
    "time"
)

func main() {
    unix := time.Now().Unix()           // int64 segundos
    t := time.Unix(unix, 0).UTC()
    fmt.Println(t.Format(time.RFC3339)) // "2024-04-09T12:00:00Z"

    loc, _ := time.LoadLocation("America/Buenos_Aires")
    fmt.Println(t.In(loc).Format(time.RFC3339))
}

Java

import java.time.Instant;
import java.time.ZoneId;
import java.time.ZonedDateTime;

long unix = Instant.now().getEpochSecond();        // segundos
Instant instant = Instant.ofEpochSecond(unix);
System.out.println(instant.toString());            // "2024-04-09T12:00:00Z"

ZonedDateTime zdt = instant.atZone(ZoneId.of("America/Mexico_City"));
System.out.println(zdt.toString());

Rust

use std::time::{SystemTime, UNIX_EPOCH};

fn main() {
    let unix = SystemTime::now()
        .duration_since(UNIX_EPOCH)
        .expect("El tiempo retrocedió")
        .as_secs();   // u64 segundos

    println!("{}", unix);  // ej.: 1712620800
}

Tabla de Formatos de Timestamp Comunes

Formato Ejemplo Usado en
Unix (segundos) 1712620800 Unix/Linux, APIs POSIX
Unix (milisegundos) 1712620800000 JavaScript, Java
Unix (microsegundos) 1712620800000000 PostgreSQL, algunas APIs
Unix (nanosegundos) 1712620800000000000 Go, Rust
ISO 8601 UTC 2024-04-09T12:00:00Z APIs REST, bases de datos
ISO 8601 con offset 2024-04-09T20:00:00+08:00 Apps de calendario
RFC 2822 Tue, 09 Apr 2024 12:00:00 +0000 Cabeceras de email
RFC 3339 2024-04-09T12:00:00Z Protocolos de Internet
Fecha HTTP Tue, 09 Apr 2024 12:00:00 GMT Cabeceras HTTP

Aritmética de Timestamps

Como un Unix timestamp es simplemente un número, la aritmética sobre timestamps es trivial.

Calcular la duración entre dos timestamps:

start = 1712620800
end   = 1712707200
duracion_segundos = end - start   # 86400 segundos = exactamente 1 día

Encontrar una fecha futura o pasada:

const now = Math.floor(Date.now() / 1000);
const unaSemanaDespues = now + 7 * 24 * 60 * 60;   // +604800 segundos
const treintaDiasAtras = now - 30 * 24 * 60 * 60;  // -2592000 segundos

Duraciones comunes en segundos:

Duración Segundos
1 minuto 60
1 hora 3.600
1 día 86.400
1 semana 604.800
30 días 2.592.000
1 año (365 días) 31.536.000

Nota: para aritmética con conciencia de calendario (ej.: "añadir 1 mes"), usa una librería de fechas en lugar de segundos brutos, porque los meses tienen diferentes longitudes y el DST puede hacer que algunos días tengan 23 o 25 horas.

Casos de Uso

Registro de aplicaciones: Las entradas de registro con Unix timestamps pueden ordenarse, filtrarse y compararse entre sistemas distribuidos que funcionan en diferentes zonas horarias, sin ambigüedad.

APIs REST: Devolver timestamps como enteros Unix evita la interpretación de zona horaria en el servidor. El cliente lee el entero y lo formatea en la zona horaria local del usuario.

Bases de datos: Almacenar timestamps como enteros (o cadenas ISO 8601) es más portable que los tipos de fecha específicos de la plataforma. El TIMESTAMPTZ de PostgreSQL almacena internamente en UTC; el DATETIME de MySQL (preferido sobre TIMESTAMP) evita el límite Y2038.

Tareas programadas y cron: Calcular "ejecutar a las 3:00 AM todos los días" en UTC evita sorpresas del DST. Muchos marcos de programación (Kubernetes CronJobs, horarios de GitHub Actions) usan UTC por convención.

Expiración de caché y TTL: Las cabeceras HTTP Cache-Control: max-age=3600 y Expires usan Unix timestamps absolutos o segundos relativos; las CDNs y los navegadores dependen de la aritmética precisa de timestamps para invalidar cachés.

Event sourcing y registros de auditoría: Los registros de eventos inmutables requieren timestamps que ordenen inequívocamente los eventos. Los Unix timestamps, especialmente a resolución de nanosegundos, proporcionan esta garantía incluso para sistemas de alto rendimiento.

Buenas Prácticas

  1. Siempre almacena timestamps en UTC. Nunca almacenes hora local en una base de datos. Convierte a hora local solo en la capa de presentación.

  2. Usa enteros de 64 bits. Evita int32 para timestamps en cualquier código nuevo. Incluso si tu sistema actualmente maneja solo fechas en el futuro cercano, 64 bits es el valor predeterminado seguro.

  3. Usa ISO 8601 para serialización legible por humanos. Cuando necesitas una representación de cadena en registros o APIs, ISO 8601 es inequívoco y se ordena lexicográficamente.

  4. Usa identificadores de zona horaria IANA, no offsets. "America/Madrid" es correcto; "-05:00" es frágil porque el offset cambia dos veces al año.

  5. Valida las unidades del timestamp. Antes de usar un timestamp externo, verifica si está en segundos, milisegundos u otra unidad. Una verificación rápida: un número de 10 dígitos probablemente está en segundos; 13 dígitos probablemente en milisegundos.

  6. Nunca analices fechas con expresiones regulares en código de producción. Usa la biblioteca estándar de tu lenguaje o una librería de terceros bien probada.

  7. Ten cuidado con la "medianoche". En zonas horarias que observan el DST, la medianoche puede no existir en ciertas fechas (transiciones de avance de primavera). Usa el mediodía (12:00 UTC) como hora "representativa" segura para cálculos de solo fecha.

  8. Prueba cerca de las transiciones DST. Si tu aplicación involucra programación o cálculos de tiempo, escribe pruebas que ejerciten específicamente los límites de avance de primavera y retroceso de otoño para las zonas horarias relevantes.

Preguntas Frecuentes

P: ¿Qué representa el Unix timestamp 0?
R: El 1 de enero de 1970, 00:00:00 UTC — el epoch de Unix. Los timestamps negativos representan fechas anteriores a 1970.

P: ¿Puedo usar timestamps para ordenar?
R: Sí. Como un Unix timestamp es un entero monotónicamente creciente, ordenar por timestamp es equivalente a ordenar cronológicamente.

P: ¿Está el tiempo Unix afectado por los segundos bisiestos?
R: POSIX define el tiempo Unix como si cada día tuviera exactamente 86.400 segundos, lo que significa que los segundos bisiestos no se cuentan. Un timestamp POSIX es técnicamente "tiempo Unix" o "tiempo POSIX", no el "verdadero" Tiempo Atómico Internacional (TAI). En la práctica, esto rara vez importa para el código de aplicación.

P: ¿Cuál es la fecha máxima representable con un Unix timestamp?
R: Con un entero de 64 bits con signo, el máximo corresponde al año 292.277.026.596. Con un entero de 32 bits con signo, es el 2038-01-19 03:14:07 UTC.

P: ¿Cómo obtengo el Unix timestamp actual en mi navegador?
R: Math.floor(Date.now() / 1000) en la consola del navegador devuelve el Unix timestamp actual en segundos.

P: ¿Por qué mi timestamp muestra 1970-01-01 cuando lo convierto?
R: Casi con certeza estás pasando milisegundos a una función que espera segundos (o viceversa). Divide por 1000 si ves una fecha en el futuro lejano; multiplica por 1000 si ves el 1 de enero de 1970.