Convertir timestamp a fecha: tabla de referencia y conversiones SQL

Valores epoch notables, conversiones SQL por motor y los límites de 2038.

Sin registro, sin rastreo

Un timestamp Unix es un solo número entero: la cantidad de segundos transcurridos desde el 1 de enero de 1970 a las 00:00:00 UTC. No lleva zona horaria, ni formato, ni ambigüedad, y por eso lo usan sin parar las bases de datos, los archivos de log, los JWT y las APIs. El precio de esa simplicidad es que un epoch en crudo no lo lee nadie: 1700000000 lo mismo puede ser la semana pasada que hace diez años.

Esta página es la tabla de consulta para ese problema. Abajo tienes los valores epoch más conocidos con su fecha UTC exacta, un truco para distinguir segundos de milisegundos contando dígitos, la expresión de conversión para cada motor SQL importante y los valores límite donde el tiempo de 32 bits se agota. Todas las fechas de esta página se calcularon, no se recordaron.

¿Segundos o milisegundos? Cuenta los dígitos

El error más común al manejar epochs es pasarle un valor en milisegundos a una función que espera segundos, lo que te deja aterrizando por el año 58 000. Casi nunca hace falta adivinar: la magnitud del número te dice la unidad. Para cualquier fecha de la época actual, contar dígitos basta para decidir.

DígitosUnidadEl mismo instante expresado así
10Segundos1785287134
13Milisegundos1785287134000
16Microsegundos1785287134000000
19Nanosegundos1785287134000000000
18Ticks de .NET (100 ns desde 0001-01-01)639208839340000000
18FILETIME de Windows (100 ns desde 1601-01-01)134297607340000000
5Número de serie de Excel46232

Si un valor tiene 13 dígitos y termina en tres ceros, casi seguro son milisegundos generados a partir de una fuente en segundos enteros. Java, JavaScript y Kafka usan milisegundos por defecto; C, Python, Go, PostgreSQL y la shell de Unix usan segundos. Los claims de un JWT (iat, exp, nbf) siempre van en segundos según el RFC 7519, y eso tumba a quien programa en JavaScript, porque Date.now() no.

Conversión por motor de base de datos

Cada motor lo escribe distinto, y las diferencias no son cosméticas: cambian el tipo devuelto y la zona horaria. La columna del centro convierte un epoch en segundos a fecha; la de la derecha hace el camino inverso.

MotorEpoch a fechaFecha a epoch
PostgreSQLto_timestamp(1700000000)EXTRACT(EPOCH FROM ts)::bigint
MySQL / MariaDBFROM_UNIXTIME(1700000000)UNIX_TIMESTAMP(dt)
SQL ServerDATEADD(SECOND, 1700000000, '19700101')DATEDIFF_BIG(SECOND, '19700101', dt)
OracleTIMESTAMP '1970-01-01 00:00:00' + NUMTODSINTERVAL(1700000000, 'SECOND')(CAST(ts AS DATE) - DATE '1970-01-01') * 86400
SQLitedatetime(1700000000, 'unixepoch')CAST(strftime('%s', dt) AS INTEGER)

Tres advertencias que causan incidentes reales. El to_timestamp de PostgreSQL devuelve timestamp with time zone, así que se muestra según el parámetro TimeZone del cliente y no en UTC: agrega AT TIME ZONE 'UTC' si necesitas una salida estable. La documentación de MySQL dice que FROM_UNIXTIME devuelve el valor en la zona horaria de la sesión, o sea que la misma consulta le da resultados distintos a dos clientes distintos. Y en SQL Server 2017 hasta 2022 el argumento number de DATEADD es un int, así que DATEADD(MILLISECOND, 1700000000000, ...) se desborda; convierte los milisegundos en dos pasos.

-- SQL Server: milisegundos sin desbordar el int
SELECT DATEADD(MILLISECOND, 1700000000000 % 1000,
         DATEADD(SECOND, 1700000000000 / 1000, '19700101'));

-- PostgreSQL: forzar la salida en UTC
SELECT to_timestamp(1700000000) AT TIME ZONE 'UTC';
Cómo sortear las dos trampas más comunes por motor

Convertir timestamp a fecha en Excel y Google Sheets

Las hojas de cálculo no guardan epochs. Guardan un número de serie de días contado desde el 30 de diciembre de 1899, así que convertir significa dividir entre los segundos que tiene un día y sumar la constante 25569, que es el número de serie del 1 de enero de 1970. Después dale formato de fecha a la celda o solo verás un decimal.

=A1/86400 + 25569          → epoch en segundos a fecha
=A1/86400000 + 25569       → epoch en milisegundos a fecha
=(A1 - 25569) * 86400      → fecha de vuelta a epoch en segundos
Fórmulas para Excel y Google Sheets

La constante 25569 parece arbitraria pero no lo es: incluye un desfase que Excel arrastra a propósito. Excel trata 1900 como año bisiesto, y no lo fue, así que sus números de serie van un día adelantados para cualquier fecha posterior a febrero de 1900. Como 25569 se calculó bajo esa misma suposición equivocada, los dos errores se cancelan y las fechas de 1970 en adelante salen correctas.

Valores epoch notables

Epoch (segundos)Fecha y hora UTCPor qué importa
01970-01-01 00:00:00 UTCLa época misma
11970-01-01 00:00:01 UTCUn segundo después de la época
864001970-01-02 00:00:00 UTCExactamente un día
10000000002001-09-09 01:46:40 UTCEl «billennium» — muy celebrado entre la gente de Unix
12345678902009-02-13 23:31:30 UTCDígitos consecutivos — el valor de prueba clásico
15000000002017-07-14 02:40:00 UTC1500 millones exactos
16000000002020-09-13 12:26:40 UTC1600 millones exactos
17000000002023-11-14 22:13:20 UTC1700 millones exactos
17356896002025-01-01 00:00:00 UTCInicio de 2025, UTC
17672256002026-01-01 00:00:00 UTCInicio de 2026, UTC
18000000002027-01-15 08:00:00 UTC1800 millones exactos
20000000002033-05-18 03:33:20 UTC2000 millones exactos
21459168002038-01-01 00:00:00 UTCInicio de 2038 — el último año nuevo que sobrevive el entero de 32 bits con signo
21474836472038-01-19 03:14:07 UTCMáximo de INT32 — el problema del año 2038
21474836482038-01-19 03:14:08 UTCUn segundo después — retrocede a 1901 si se guarda como entero de 32 bits con signo
42949672952106-02-07 06:28:15 UTCMáximo de UINT32
-11969-12-31 23:59:59 UTCUn segundo antes de la época
-21474836481901-12-13 20:45:52 UTCMínimo de INT32
2534023007999999-12-31 23:59:59 UTCÚltimo segundo del año 9999 — límite superior habitual

Convertir desde código

LenguajeEpoch a fechaAhora como epoch
Pythondatetime.fromtimestamp(1700000000, tz=timezone.utc)int(dt.timestamp())
JavaScriptnew Date(1700000000 * 1000)Math.floor(Date.now() / 1000)
Gotime.Unix(1700000000, 0).UTC()t.Unix()
JavaInstant.ofEpochSecond(1700000000)instant.getEpochSecond()
PHPdate("Y-m-d H:i:s", 1700000000)time()
RubyTime.at(1700000000).utct.to_i
Bash (GNU)date -u -d @1700000000date +%s
PowerShell[DateTimeOffset]::FromUnixTimeSeconds(1700000000)[DateTimeOffset]::UtcNow.ToUnixTimeSeconds()

El problema del año 2038 y otros límites

Un entero de 32 bits con signo se detiene en 2 147 483 647. Un sistema que guarde el tiempo Unix de esa forma se queda sin espacio a las 03:14:07 UTC del 19 de enero de 2038, y al segundo siguiente da la vuelta hasta diciembre de 1901. Esto no es hipotético para dispositivos embebidos, sistemas de archivos viejos y cualquier esquema que haya elegido INT en vez de BIGINT.

ValorInstanteQué se rompe
21474836472038-01-19 03:14:07 UTCDesbordamiento de segundos en 32 bits con signo — el problema del año 2038
42949672952106-02-07 06:28:15 UTCDesbordamiento de segundos en 32 bits sin signo
-21474836481901-12-13 20:45:52 UTCValor más bajo que admite un epoch de 32 bits con signo
2534023007999999-12-31 23:59:59 UTCÚltimo segundo del año 9999 — límite superior de muchos tipos fecha en SQL
8640000000000000 (ms)+275760-09-13Valor máximo que puede representar un Date de JavaScript

La solución no tiene ningún encanto: guarda los epochs en columnas de 64 bits. Una cuenta de segundos en 64 bits con signo se agota dentro de unos 292 000 millones de años, bastante después del punto en que deja de ser tu problema. Si hoy estás eligiendo el tipo de una columna, BIGINT o un tipo timestamp nativo sirven igual; INT es una mina enterrada.

Detalles que conviene tener claros

  1. El tiempo Unix ignora los segundos intercalares. POSIX exige que cada día tenga exactamente 86 400 segundos, así que los 27 segundos intercalares insertados en UTC desde 1972 sencillamente no se cuentan. Un epoch es un cálculo de calendario, no un conteo de segundos físicos transcurridos.
  2. Un epoch no tiene zona horaria. El número siempre está referido a UTC; la zona horaria solo aparece cuando lo formateas. Si dos servidores muestran fechas distintas para el mismo entero, están formateando distinto, no guardando distinto.
  3. Los epochs negativos son válidos y representan fechas anteriores a 1970. Muchas librerías y algunas bases de datos los manejan mal, así que pruébalo si guardas fechas de nacimiento de esta forma.
  4. Ojo con los epochs guardados como texto. Ordenar «9999999999» contra «10000000000» de forma lexicográfica los deja al revés, y el error solo aparece cuando cambia la cantidad de dígitos.
  5. Un timestamp con resolución de segundos no puede expresar el orden dentro del mismo segundo. Si necesitas secuenciar eventos, guarda milisegundos o agrega una columna de desempate.

Convierte tus propios valores

Esta tabla cubre los valores que la gente consulta una y otra vez, pero no el que tienes ahora mismo en tu archivo de log. El Convertidor de Timestamp Unix de este sitio toma cualquier epoch y te lo muestra a la vez en tu zona horaria local, en UTC y en ISO 8601, detecta solo si pegaste segundos o milisegundos, y hace la conversión al revés desde un selector de fecha. Además mantiene un timestamp actual en vivo listo para copiar. Como todo lo de aquí, corre por completo en tu navegador: los valores que pegues no se suben a ningún lado.

Herramientas relacionadas