Engineering · 22 de septiembre de 2026

Conversión de marcas de tiempo Unix explicada: segundos de época, milisegundos e ISO 8601

Las marcas de tiempo Unix parecen un solo entero hasta que una confusión de unidades convierte hoy en 1970. Segundos de época frente a milisegundos, ISO 8601, zonas horarias y una chuleta de conversión para los errores de siempre.

Cualquier sistema que almacena un momento en el tiempo termina haciendo la misma pregunta: ¿esta cifra está en segundos o en milisegundos? Las marcas de tiempo Unix parecen triviales — un entero que cuenta los segundos transcurridos desde el 1 de enero de 1970 — y por eso mismo se tratan mal. Un valor equivocado por un factor de 1000, una fecha en 1970, un desfase de zona horaria que solo aparece en usuarios del otro hemisferio: todo sale de los mismos pocos malentendidos.

Este artículo explica qué mide de verdad una marca de tiempo Unix, cómo se distinguen segundos y milisegundos, cómo encaja ISO 8601 y cómo convertir entre formatos sin adivinar.

Qué es de verdad una marca de tiempo Unix

Una marca de tiempo Unix — también llamada época — es el número de segundos transcurridos desde el 00:00:00 UTC del 1 de enero de 1970, la época Unix. Es un entero sin información de zona horaria: la misma cifra describe el mismo instante en todo el planeta.

Al no llevar zona horaria, la época es un formato de intercambio natural para las máquinas. Las APIs, los registros, las bases de datos y las colas de mensajes guardan marcas de tiempo; las personas leen fechas. La conversión entre ambos mundos es donde viven los errores.

Conviene notar lo que una marca de tiempo no contiene: zona horaria, configuración regional ni calendario. 1758537600 es un instante. Que alguien en Bangkok vea las 21:00 y alguien en Madrid las 14:00 depende solo de cómo se presente.

Segundos frente a milisegundos: el error más frecuente

Dos convenciones conviven y las dos están por todas partes:

  • Segundos — hoy 10 dígitos, por ejemplo 1758537600. El Unix tradicional, Unix() de Go, getEpochSecond() de Java, Redis y la mayoría de las bases de datos usan esta unidad.
  • Milisegundos — 13 dígitos, por ejemplo 1758537600000. Date.now() de JavaScript, getTime() de Java y la mayoría de las APIs del navegador usan esta unidad.

Confundir la unidad hace saltar la fecha al año 1970 o 2286. No existe una regla universal para adivinar la unidad, así que la vía fiable es conocer el contrato de la fuente. Si hay que intentar adivinar, 10 dígitos suelen ser segundos y 13 suelen ser milisegundos — pero adivinar es el error, no la solución.

Regla: guarde la unidad junto al valor. Use un nombre de columna (created_at_ms), un campo explícito de la API o una propiedad unit. Cualquier cosa es mejor que un entero desnudo llamado time.

ISO 8601: el lado legible para humanos

Las cadenas ISO 8601 son la contraparte de los números de época: legibles, ordenables en UTC y no ambiguas cuando llevan desplazamiento.

2026-09-22T14:00:00Z       # UTC, indicado por la Z final
2026-09-22T14:00:00+02:00  # el mismo instante en hora local de Berlín
2026-09-22T14:00:00.123Z   # conserva los milisegundos

La Z final y el desplazamiento numérico no son adorno. Sin uno de los dos, la cadena no tiene zona horaria y su código tiene que adivinar — y así es como «la misma hora» se convierte silenciosamente en un desfase de tres horas.

Zonas horarias y UTC

Almacene y compare en UTC, y convierta a una zona local en la capa de presentación, solo cuando vaya a mostrarlo a una persona.

const now = Date.now();                 // milisegundos desde la época
const seconds = Math.floor(now / 1000); // segundos desde la época
new Date(seconds * 1000).toISOString(); // "2026-09-22T14:00:00.000Z"

Dos reglas evitan la mayoría de los problemas de zona horaria:

  • Nunca compare una hora local ingenua con otra. Serialice ambas a instantes y compare después.
  • Conserve el desplazamiento junto al valor cuando importe la zona del usuario (citas, horarios, periodos de facturación). Un instante en UTC más un identificador IANA como Europe/Madrid es mejor que un desplazamiento fijo, porque los desplazamientos fijos cambian con el horario de verano.

Chuleta de conversión

Convertir JavaScript Python
Milisegundos a cadena de fecha new Date(1758537600000).toISOString() datetime.fromtimestamp(1758537600, tz=timezone.utc)
Cadena de fecha a segundos Math.floor(Date.parse(s) / 1000) int(dt.replace(tzinfo=timezone.utc).timestamp())
Segundos a milisegundos seconds * 1000 seconds * 1000
Hora actual Date.now() (milisegundos) int(time.time()) (segundos)

Fíjese en que Date.now() devuelve milisegundos mientras time.time() devuelve segundos: una ilustración compacta de que la unidad es una convención por lenguaje, no un estándar universal.

Errores que conviene evitar

  • Escalar por 1000 «por si acaso». Decida según el contrato, nunca según cuántos dígitos tenga la cifra.
  • Guardar hora local sin desplazamiento. El horario de verano romperá la aritmética tarde o temprano.
  • Parsear partiendo cadenas a mano. Use el analizador de la biblioteca estándar: ISO 8601 trae datos de semana, formato básico y fraccionarios que rompen el código casero.
  • Formatos de fecha dentro de SQL. Mantenga el valor numérico o en UTC en la base de datos y formatee en la aplicación, donde controla el idioma y la zona.
  • Usar la marca de tiempo completa como identificador humano. Cuando las personas la leen en voz alta, se dejan caer dígitos. Reduzca o hashee si necesita una referencia corta.

Pruébalo

Pegue un valor de época o una cadena de fecha en un conversor de marcas de tiempo para alternar entre segundos, milisegundos, ISO 8601 y su hora local. La conversión ocurre en su navegador, así que ninguna marca de tiempo — sensible o no — tiene que salir de su equipo para ser legible.