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 rastreoUn 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ígitos | Unidad | El mismo instante expresado así |
|---|---|---|
| 10 | Segundos | 1785287134 |
| 13 | Milisegundos | 1785287134000 |
| 16 | Microsegundos | 1785287134000000 |
| 19 | Nanosegundos | 1785287134000000000 |
| 18 | Ticks de .NET (100 ns desde 0001-01-01) | 639208839340000000 |
| 18 | FILETIME de Windows (100 ns desde 1601-01-01) | 134297607340000000 |
| 5 | Número de serie de Excel | 46232 |
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.
| Motor | Epoch a fecha | Fecha a epoch |
|---|---|---|
| PostgreSQL | to_timestamp(1700000000) | EXTRACT(EPOCH FROM ts)::bigint |
| MySQL / MariaDB | FROM_UNIXTIME(1700000000) | UNIX_TIMESTAMP(dt) |
| SQL Server | DATEADD(SECOND, 1700000000, '19700101') | DATEDIFF_BIG(SECOND, '19700101', dt) |
| Oracle | TIMESTAMP '1970-01-01 00:00:00' + NUMTODSINTERVAL(1700000000, 'SECOND') | (CAST(ts AS DATE) - DATE '1970-01-01') * 86400 |
| SQLite | datetime(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';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 segundosLa 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 UTC | Por qué importa |
|---|---|---|
| 0 | 1970-01-01 00:00:00 UTC | La época misma |
| 1 | 1970-01-01 00:00:01 UTC | Un segundo después de la época |
| 86400 | 1970-01-02 00:00:00 UTC | Exactamente un día |
| 1000000000 | 2001-09-09 01:46:40 UTC | El «billennium» — muy celebrado entre la gente de Unix |
| 1234567890 | 2009-02-13 23:31:30 UTC | Dígitos consecutivos — el valor de prueba clásico |
| 1500000000 | 2017-07-14 02:40:00 UTC | 1500 millones exactos |
| 1600000000 | 2020-09-13 12:26:40 UTC | 1600 millones exactos |
| 1700000000 | 2023-11-14 22:13:20 UTC | 1700 millones exactos |
| 1735689600 | 2025-01-01 00:00:00 UTC | Inicio de 2025, UTC |
| 1767225600 | 2026-01-01 00:00:00 UTC | Inicio de 2026, UTC |
| 1800000000 | 2027-01-15 08:00:00 UTC | 1800 millones exactos |
| 2000000000 | 2033-05-18 03:33:20 UTC | 2000 millones exactos |
| 2145916800 | 2038-01-01 00:00:00 UTC | Inicio de 2038 — el último año nuevo que sobrevive el entero de 32 bits con signo |
| 2147483647 | 2038-01-19 03:14:07 UTC | Máximo de INT32 — el problema del año 2038 |
| 2147483648 | 2038-01-19 03:14:08 UTC | Un segundo después — retrocede a 1901 si se guarda como entero de 32 bits con signo |
| 4294967295 | 2106-02-07 06:28:15 UTC | Máximo de UINT32 |
| -1 | 1969-12-31 23:59:59 UTC | Un segundo antes de la época |
| -2147483648 | 1901-12-13 20:45:52 UTC | Mínimo de INT32 |
| 253402300799 | 9999-12-31 23:59:59 UTC | Último segundo del año 9999 — límite superior habitual |
Convertir desde código
| Lenguaje | Epoch a fecha | Ahora como epoch |
|---|---|---|
| Python | datetime.fromtimestamp(1700000000, tz=timezone.utc) | int(dt.timestamp()) |
| JavaScript | new Date(1700000000 * 1000) | Math.floor(Date.now() / 1000) |
| Go | time.Unix(1700000000, 0).UTC() | t.Unix() |
| Java | Instant.ofEpochSecond(1700000000) | instant.getEpochSecond() |
| PHP | date("Y-m-d H:i:s", 1700000000) | time() |
| Ruby | Time.at(1700000000).utc | t.to_i |
| Bash (GNU) | date -u -d @1700000000 | date +%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.
| Valor | Instante | Qué se rompe |
|---|---|---|
| 2147483647 | 2038-01-19 03:14:07 UTC | Desbordamiento de segundos en 32 bits con signo — el problema del año 2038 |
| 4294967295 | 2106-02-07 06:28:15 UTC | Desbordamiento de segundos en 32 bits sin signo |
| -2147483648 | 1901-12-13 20:45:52 UTC | Valor más bajo que admite un epoch de 32 bits con signo |
| 253402300799 | 9999-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-13 | Valor 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
- 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.
- 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.
- 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.
- 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.
- 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.