Instant: qué es, marca de tiempo y aplicación en desarrollo

Autor: IT Sectr Publicado: 2026-07-13 Tiempo de lectura: 9 min

Instant — una clase inmutable del paquete java.time que representa un punto en la línea de tiempo en UTC con precisión de nanosegundos. A diferencia de LocalDateTime, Instant no contiene fecha y hora en un formato legible para humanos — es una representación mecánica de un momento. Según la especificación de Oracle Java 17 (2024), Instant está diseñado para el intercambio mecánico de marcas de tiempo y es un análogo de System.currentTimeMillis(), pero con precisión de nanosegundos.

Puntos Clave

  • Instant — un momento en el tiempo en UTC con precisión de nanosegundos, inmutable y thread-safe.
  • Almacena el tiempo como la cantidad de segundos desde la época (1970-01-01T00:00:00Z) más nanosegundos.
  • Instant.now() devuelve el momento actual en UTC independientemente de la zona horaria del dispositivo.
  • Para la conversión a un formato legible, se utiliza atZone(ZoneId), que devuelve un ZonedDateTime.
  • Instant es el tipo preferido para transmitir marcas de tiempo en API y sistemas distribuidos.

¿Qué es Instant?

Instant es una clase que modela un único punto en la línea de tiempo. Su representación interna consta de dos campos: long seconds (la cantidad de segundos desde 1970-01-01T00:00:00Z) e int nanos (nanosegundos dentro del segundo actual, de 0 a 999999999).

El rango de valores de Instant es de -31557014167219200 a 31556889864403199 segundos desde la época, cubriendo aproximadamente 292 millones de años en ambas direcciones. Esto es suficiente para cualquier tarea práctica, incluidos los cálculos astronómicos.

Según Baeldung (2024), Instant es un puente entre los tipos legibles para humanos (LocalDateTime, ZonedDateTime) y los formatos de máquina (timestamp en milisegundos). Instant se utiliza para registro, almacenamiento en caché, sincronización y todas las tareas donde un momento absoluto en el tiempo es importante.

La clase implementa las interfaces Comparable (para comparar momentos) y Temporal (para usar en la API común de java.time). Instant es inmutable — todos los métodos devuelven un nuevo objeto.

Instant vs Date vs Long

Antes de Java 8, se utilizaban java.util.Date y System.currentTimeMillis() para trabajar con momentos en el tiempo. Ambos enfoques tienen inconvenientes. Date es mutable, no es thread-safe, almacena el tiempo en milisegundos desde la época, pero los nombres de sus métodos están desactualizados (getYear() devuelve 116 para 2016).

Long (un timestamp simple) es rápido y compacto, pero no tiene soporte incorporado para nanosegundos, no se muestra en un formato legible y requiere análisis manual durante la depuración. El enfoque Long tampoco distingue tipos de datos — un desarrollador podría pasar un valor incorrecto.

Instant resuelve todos estos problemas. Es inmutable, contiene información explícita de precisión (segundos + nanosegundos), se serializa al formato ISO-8601 “2026-07-21T15:00:00Z” y tiene una API rica para conversiones. Según SonarSource (2024), Instant es el reemplazo recomendado de Date en todos los proyectos nuevos.

Crear y Leer Instant

El momento actual se obtiene mediante Instant.now(). A diferencia de LocalDateTime.now(), Instant.now() siempre devuelve la hora en UTC, ignorando la zona horaria del dispositivo. Esto lo hace ideal para marcas de tiempo de servidor.

Desde valores existentes: Instant.ofEpochSecond(long epochSecond) — desde segundos desde la época, Instant.ofEpochMilli(long epochMilli) — desde milisegundos, Instant.parse(CharSequence) — desde una cadena ISO-8601 (“2026-07-21T15:00:00Z”).

Para lectura: getEpochSecond() — la cantidad de segundos desde la época, toEpochMilli() — la cantidad de milisegundos, getNano() — nanosegundos. El método toString() devuelve una cadena en formato ISO-8601.

kotlin
val now = Instant.now()

val fromSeconds = Instant.ofEpochSecond(1784700000)
val fromMillis = Instant.ofEpochMilli(1784700000000)
val parsed = Instant.parse("2026-07-21T15:00:00Z")

val epochSecond = now.getEpochSecond()
val epochMilli = now.toEpochMilli()
val nanos = now.getNano()

Convertir Instant a Otros Formatos

Instant se convierte a ZonedDateTime mediante atZone(ZoneId). Por ejemplo, Instant.now().atZone(ZoneId.of(“Europe/Moscow”)) devuelve un ZonedDateTime para Moscú. Sin una zona, la conversión es imposible — Instant no contiene información de calendario.

Para convertir Instant a LocalDateTime: atZone(ZoneId).toLocalDateTime(). Este enfoque es explícito y no pierde información. Conversión inversa: LocalDateTime.atZone(ZoneId).toInstant().

Para compatibilidad con java.util.Date: Date.from(instant) y date.toInstant(). Esta es una conversión bidireccional que conserva la precisión hasta milisegundos (Date no soporta nanosegundos). Para java.sql.Timestamp, use Timestamp.from(instant) con soporte de nanosegundos.

kotlin
val instant = Instant.now()

val zoned = instant.atZone(ZoneId.of("Europe/Moscow"))
val localDateTime = instant
    .atZone(ZoneId.systemDefault())
    .toLocalDateTime()

val oldDate = Date.from(instant)
val backToInstant = oldDate.toInstant()

Instant y Zonas Horarias

La característica clave de Instant es que es completamente independiente de las zonas horarias. Instant.now() devuelve el mismo resultado en cualquier dispositivo en cualquier parte del mundo. Esto se logra fijando la hora en UTC.

Una zona horaria solo es necesaria para mostrar Instant a un humano. Para esto, se utiliza atZone(ZoneId). ZoneId.systemDefault() devuelve la zona horaria del dispositivo configurada en el sistema operativo. ZoneOffset.UTC es la constante para UTC.

En sistemas distribuidos, se recomienda almacenar y transmitir todas las marcas de tiempo en Instant (o OffsetDateTime con ZoneOffset.UTC). La conversión a hora local se realiza solo en el cliente antes de mostrar al usuario. Esto evita confusiones con las zonas horarias.

Sincronización de Tiempo mediante Instant

En aplicaciones de Android distribuidas, la sincronización de tiempo es crítica para el correcto funcionamiento del caché, las notificaciones y la edición colaborativa. Instant es la opción natural para esta tarea gracias a su anclaje en UTC.

Al comparar marcas de tiempo de diferentes dispositivos, hay que considerar que los relojes del sistema pueden divergir. Se recomienda usar la hora del servidor como referencia. El servidor devuelve Instant en UTC, y el cliente lo compara con el Instant local solo para cálculos relativos.

Para calcular la diferencia entre dos momentos, use Duration.between(Instant start, Instant end). Este método devuelve una Duration que se puede convertir a horas, minutos, segundos. Los métodos isAfter() e isBefore() permiten comparar momentos.

kotlin
fun isCacheExpired(
    cachedAt: Instant,
    ttlMinutes: Long
): Boolean {
    val elapsed = Duration.between(cachedAt, Instant.now())
    return elapsed.toMinutes() >= ttlMinutes
}

Ejemplos Prácticos en Android

El primer ejemplo es el registro de eventos con una marca de tiempo. Instant se guarda en la base de datos Room y se envía al servidor. La marca de tiempo se registra en UTC para una interpretación inequívoca.

kotlin
data class EventLog(
    val id: Long = 0,
    val eventName: String,
    val timestamp: Instant
)

class Converters {
    @TypeConverter
    fun fromInstant(value: Instant?): Long? {
        return value?.toEpochMilli()
    }

    @TypeConverter
    fun toInstant(value: Long?): Instant? {
        return value?.let { Instant.ofEpochMilli(it) }
    }
}

El segundo ejemplo es determinar el tiempo transcurrido desde un evento. Usamos Duration.between para mostrar “hace 5 minutos”, “hace 2 horas” — un formato común en mensajeros y redes sociales.

kotlin
fun timeAgo(instant: Instant): String {
    val duration = Duration.between(instant, Instant.now())
    return when {
        duration.toMinutes() < 1 -> "just now"
        duration.toHours() < 1 -> "${duration.toMinutes()} min ago"
        duration.toDays() < 1 -> "${duration.toHours()} h ago"
        else -> "${duration.toDays()} d ago"
    }
}

El tercer ejemplo es la sincronización de datos entre el servidor y el cliente. Usamos Instant para rastrear la hora de la última actualización.

kotlin
class SyncManager {
    private var lastSyncAt: Instant? = null

    fun sync() {
        val syncStart = Instant.now()
        // server request with lastSyncAt
        lastSyncAt = syncStart
    }

    fun shouldSync(intervalMinutes: Long): Boolean {
        val last = lastSyncAt ?: return true
        return Duration.between(last, Instant.now())
            .toMinutes() >= intervalMinutes
    }
}

Errores Comunes

El primer error es usar Instant.now().toString() para mostrar al usuario. Instant genera el formato UTC “2026-07-21T15:00:00Z”, que es ilegible para los humanos. Siempre convierta Instant mediante atZone() a la zona horaria local antes de mostrarlo.

El segundo error es perder nanosegundos al convertir a java.util.Date. Date solo admite milisegundos. Si Instant tiene nanosegundos, se descartarán en Date.from(instant). Use Instant.truncatedTo(ChronoUnit.MILLIS) para especificar explícitamente la precisión.

El tercer error es la confusión entre toEpochMilli() y getEpochSecond(). toEpochMilli() devuelve la cantidad de milisegundos desde la época (long), mientras que getEpochSecond() devuelve la cantidad de segundos (long). Confundir estos métodos puede resultar en un error de 1000x.

El cuarto error es asumir que Instant.now() está sincronizado en todos los dispositivos. Los relojes del sistema pueden diferir por minutos o incluso horas. Para operaciones críticas en el tiempo (autenticación, pagos), use Instant del servidor como fuente de verdad.

Preguntas Frecuentes

¿En qué se diferencia Instant de System.currentTimeMillis()?

System.currentTimeMillis() devuelve un long — la cantidad de milisegundos desde la época sin vinculación de zona horaria. Instant proporciona la misma funcionalidad pero con precisión de nanosegundos y una API rica para conversiones, comparaciones y compatibilidad con java.time.

¿Cómo guardar Instant en Room Database?

Room no admite Instant directamente. Use TypeConverter que convierta Instant a Long (toEpochMilli) y viceversa (Instant.ofEpochMilli). Para precisión de nanosegundos, guarde dos campos: época-segundos y nanosegundos.

¿Se puede usar Instant como clave en HashMap?

Sí, Instant es inmutable e implementa correctamente equals() y hashCode(). Dos Instant con el mismo valor serán iguales. Esto lo convierte en una clave confiable para HashMap y otras colecciones, a diferencia de java.util.Date que es mutable.

¿Cómo obtener la diferencia entre dos Instant?

Use Duration.between(start, end) para obtener una Duration o ChronoUnit.SECONDS.between(start, end) para la diferencia en segundos (long). Duration proporciona los métodos toMinutes(), toHours(), toDays() y toNanos().

¿Por qué Instant.parse() requiere un sufijo Z o desplazamiento?

Instant está diseñado como un punto absoluto en la línea de tiempo. Sin especificar una zona horaria o UTC, el análisis es imposible porque Instant no contiene información de calendario. El sufijo “Z” denota desplazamiento cero (UTC) y es obligatorio para el formato ISO-8601.

Resumen

  • Instant — una clase inmutable para un momento absoluto en el tiempo en UTC con precisión de nanosegundos, preferida para marcas de tiempo en sistemas distribuidos.
  • A diferencia de java.util.Date, Instant es inmutable, thread-safe y tiene precisión de nanosegundos. A diferencia de Long — está explícitamente tipado y no permite confusión con otros valores numéricos.
  • Para mostrar al usuario, Instant se convierte mediante atZone(ZoneId) a ZonedDateTime, de lo contrario la hora se mostrará en UTC.
  • Para transmisión en API, use Instant.toString() (ISO-8601) o toEpochMilli() para compatibilidad con formatos antiguos.
  • Al trabajar con Room, guarde Instant como Long mediante TypeConverter usando el método toEpochMilli().
  • Para calcular el tiempo transcurrido, use Duration.between(), que maneja correctamente los nanosegundos.
  • No confíe en la sincronización del reloj del dispositivo — para operaciones críticas, use Instant del servidor como fuente de verdad.

Desarrollaremos una aplicación móvil llave en mano

IT Sectr crea aplicaciones para iOS y Android para startups y empresas desde 2017. Le asesoraremos y le propondremos la mejor solución.

Discutir el proyecto

Lea también