Instant: co to je, časové razítko a aplikace ve vývoji

Autor: IT Sectr Publikováno: 2026-07-13 Doba čtení: 9 min

Instant — neměnná třída z balíčku java.time, představující bod na časové ose v UTC s přesností na nanosekundy. Na rozdíl od LocalDateTime, Instant neobsahuje datum a čas v člověkem čitelném formátu — jde o strojovou reprezentaci okamžiku. Podle specifikace Oracle Java 17 (2024) je Instant navržen pro strojovou výměnu časových razítek a je analogií System.currentTimeMillis(), ale s nanosekundovou přesností.

Hlavní body

  • Instant — okamžik v UTC s nanosekundovou přesností, neměnný a thread-safe.
  • Ukládá čas jako počet sekund od epochy (1970-01-01T00:00:00Z) plus nanosekundy.
  • Instant.now() vrací aktuální okamžik v UTC nezávisle na časovém pásmu zařízení.
  • Pro převod do člověkem čitelného formátu se používá atZone(ZoneId), který vrací ZonedDateTime.
  • Instant — preferovaný typ pro přenos časových razítek v API a distribuovaných systémech.

Co je Instant?

Instant — je třída modelující jediný bod na časové ose. Její vnitřní reprezentace se skládá ze dvou polí: long seconds (počet sekund od 1970-01-01T00:00:00Z) a int nanos (nanosekundy v rámci aktuální sekundy, od 0 do 999999999).

Rozsah hodnot Instant — od -31557014167219200 do 31556889864403199 sekund od epochy, což pokrývá přibližně 292 milionů let v obou směrech. To je dostatečné pro všechny praktické úkoly, včetně astronomických výpočtů.

Podle Baeldung (2024) je Instant mostem mezi člověkem čitelnými typy (LocalDateTime, ZonedDateTime) a strojovými formáty (timestamp v milisekundách). Instant se používá pro logování, ukládání do mezipaměti, synchronizaci a všechny úkoly, kde je důležitý absolutní časový okamžik.

Třída implementuje rozhraní Comparable (pro porovnávání okamžiků) a Temporal (pro použití v obecném API java.time). Instant je neměnný — všechny metody vracejí nový objekt.

Instant vs Date vs Long

Před Javou 8 se pro práci s časovými okamžiky používaly java.util.Date a System.currentTimeMillis(). Oba přístupy mají nevýhody. Date je měnitelný, není thread-safe, ukládá čas v milisekundách od epochy, ale názvy metod jsou zastaralé (getYear() vrací 116 pro rok 2016).

Long (jednoduchý timestamp) je rychlý a kompaktní, ale nemá vestavěnou podporu pro nanosekundy, nezobrazuje se v čitelné podobě a vyžaduje ruční parsování při ladění. Přístup Long také nerozlišuje datový typ — vývojář může předat nesprávnou hodnotu.

Instant řeší všechny tyto problémy. Je neměnný, obsahuje explicitní informaci o přesnosti (sekundy + nanosekundy), serializuje se do formátu ISO-8601 „2026-07-21T15:00:00Z“ a má bohaté API pro převody. Podle SonarSource (2024) je Instant doporučenou náhradou za Date ve všech nových projektech.

Vytvoření a čtení Instant

Aktuální okamžik se získá pomocí Instant.now(). Na rozdíl od LocalDateTime.now() vrací Instant.now() vždy čas v UTC, ignoruje časové pásmo zařízení. To ho činí ideálním pro serverová časová razítka.

Z existujících hodnot: Instant.ofEpochSecond(long epochSecond) — ze sekund od epochy, Instant.ofEpochMilli(long epochMilli) — z milisekund, Instant.parse(CharSequence) — z řetězce ISO-8601 („2026-07-21T15:00:00Z”).

Pro čtení se používá getEpochSecond() — počet sekund od epochy, toEpochMilli() — počet milisekund, getNano() — nanosekundy. Metoda toString() vrací řetězec ve formátu 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()

Převod Instant do jiných formátů

Instant se převádí na ZonedDateTime pomocí atZone(ZoneId). Například Instant.now().atZone(ZoneId.of("Europe/Moscow")) vrátí ZonedDateTime pro Moskvu. Bez zóny je převod nemožný — Instant neobsahuje kalendářní informace.

Na LocalDateTime se Instant převádí pomocí atZone(ZoneId).toLocalDateTime(). Tento způsob je explicitní a neztrácí informace. Opačný převod — LocalDateTime.atZone(ZoneId).toInstant().

Pro kompatibilitu s java.util.Date: Date.from(instant) a date.toInstant(). Toto je obousměrný převod zachovávající přesnost až na milisekundy (Date nepodporuje nanosekundy). Pro práci s java.sql.Timestamp se používá Timestamp.from(instant) s podporou nanosekund.

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 a časová pásma

Klíčová vlastnost Instant — je zcela nezávislý na časových pásmech. Instant.now() vrací stejný výsledek na jakémkoli zařízení kdekoli na světě. Toho je dosaženo fixací času v UTC.

Časové pásmo je potřeba pouze pro zobrazení Instant člověku. K tomu slouží atZone(ZoneId). ZoneId.systemDefault() vrací časové pásmo zařízení nastavené v operačním systému. ZoneOffset.UTC — konstanta pro UTC.

V distribuovaných systémech se doporučuje ukládat a přenášet všechna časová razítka v Instant (nebo OffsetDateTime s ZoneOffset.UTC). Převod na místní čas se provádí pouze na straně klienta před zobrazením uživateli. Tím se předchází zmatkům s časovými pásmy.

Synchronizace času pomocí Instant

V distribuovaných Android aplikacích je synchronizace času kritická pro správné fungování ukládání do mezipaměti, notifikací a společné editace. Instant — přirozená volba pro tento úkol díky vazbě na UTC.

Při porovnávání časových razítek z různých zařízení je třeba vzít v úvahu, že systémové hodiny se mohou lišit. Doporučuje se používat čas serveru jako referenci. Server vrací Instant v UTC, klient porovnává s místním Instant pouze pro relativní výpočty.

Pro výpočet rozdílu mezi dvěma okamžiky se používá Duration.between(Instant start, Instant end). Tato metoda vrací Duration — dobu trvání, kterou lze převést na hodiny, minuty, sekundy. Metody isAfter() a isBefore() umožňují porovnávat okamžiky.

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

Praktické příklady v Androidu

První příklad — zaznamenávání událostí s časovým razítkem. Instant se ukládá do databáze Room a odesílá na server. Časové razítko se loguje v UTC pro jednoznačnou interpretaci.

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) }
    }
}

Druhý příklad — určení času, který uplynul od události. Používáme Duration.between pro zobrazení „před 5 minutami“, „před 2 hodinami“ — formátu běžného v messengerech a sociálních sítích.

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"
    }
}

Třetí příklad — synchronizace dat mezi serverem a klientem. Používáme Instant pro sledování času poslední aktualizace.

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

    fun sync() {
        val syncStart = Instant.now()
        // požadavek serveru s lastSyncAt
        lastSyncAt = syncStart
    }

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

Typické chyby

První chyba — použití Instant.now().toString() pro zobrazení uživateli. Instant se zobrazuje v UTC formátu „2026-07-21T15:00:00Z“, který je pro člověka nečitelný. Vždy převeďte Instant pomocí atZone() do místního časového pásma před zobrazením.

Druhá chyba — ztráta nanosekund při převodu na java.util.Date. Date podporuje pouze milisekundy. Pokud má Instant nanosekundy, budou ztraceny při Date.from(instant). Použijte Instant.truncatedTo(ChronoUnit.MILLIS) pro explicitní určení přesnosti.

Třetí chyba — záměna toEpochMilli() a getEpochSecond(). toEpochMilli() vrací počet milisekund od epochy (long), zatímco getEpochSecond() vrací počet sekund (long). Záměna těchto metod může vést k 1000násobné chybě.

Čtvrtá chyba — předpoklad, že Instant.now() je synchronizován na všech zařízeních. Systémové hodiny se mohou lišit o minuty, ba i hodiny. Pro časově kritické operace (autentizace, platby) používejte serverový Instant jako zdroj pravdy.

Často kladené otázky

Čím se Instant liší od System.currentTimeMillis()?

System.currentTimeMillis() vrací long — počet milisekund od epochy bez vazby na časové pásmo. Instant poskytuje stejnou funkcionalitu, ale s nanosekundovou přesností a bohatým API pro převody, porovnávání a kompatibilitu s java.time.

Jak uložit Instant v Room databázi?

Room přímo nepodporuje Instant. Použijte TypeConverter, který převádí Instant na Long (toEpochMilli) a zpět (Instant.ofEpochMilli). Pro nanosekundovou přesnost ukládejte dvě pole: epocha-sekundy a nanosekundy.

Lze Instant použít jako klíč v HashMap?

Ano, Instant je neměnný a správně implementuje equals() a hashCode(). Dva Instant se stejnou hodnotou budou stejné. To z něj činí spolehlivý klíč pro HashMap a další kolekce, na rozdíl od měnitelného java.util.Date.

Jak získat rozdíl mezi dvěma Instant?

Použijte Duration.between(start, end) pro získání Duration nebo ChronoUnit.SECONDS.between(start, end) pro rozdíl v sekundách (long). Duration poskytuje metody toMinutes(), toHours(), toDays() a toNanos().

Proč Instant.parse() vyžaduje příponu Z nebo offset?

Instant je navržen jako absolutní bod na časové ose. Bez uvedení časového pásma nebo UTC je parsování nemožné, protože Instant neobsahuje kalendářní informace. Přípona „Z“ označuje nulový offset (UTC) a je povinná pro formát ISO-8601.

Shrnutí

  • Instant — neměnná třída pro absolutní časový okamžik v UTC s nanosekundovou přesností, preferovaná pro časová razítka v distribuovaných systémech.
  • Na rozdíl od java.util.Date je Instant neměnný, thread-safe a má nanosekundovou přesnost. Na rozdíl od Long — je explicitně typovaný a neumožňuje záměnu s jinými číselnými hodnotami.
  • Pro zobrazení uživateli se Instant převádí pomocí atZone(ZoneId) na ZonedDateTime, jinak bude čas zobrazen v UTC.
  • Pro přenos v API používejte Instant.toString() (ISO-8601) nebo toEpochMilli() pro kompatibilitu se starými formáty.
  • Při práci s Room ukládejte Instant jako Long pomocí TypeConverter s metodou toEpochMilli().
  • Pro výpočet uplynulého času používejte Duration.between(), který správně zpracovává nanosekundy.
  • Nespoléhejte na synchronizaci hodin zařízení — pro kritické operace používejte serverový Instant jako zdroj pravdy.

Vyvineme mobilní aplikaci na klíč

IT Sectr vytváří aplikace pro iOS a Android pro startupy a podniky od roku 2017. Poradíme vám a navrhneme nejlepší řešení.

Prodiskutovat projekt

Přečtěte si také