Instant — en oföränderlig klass från paketet java.time som representerar en punkt på tidslinjen i UTC med nanosekunders precision. Till skillnad från LocalDateTime innehåller Instant inte datum och tid i ett mänskligt läsbart format — det är en maskinrepresentation av ögonblicket. Enligt specifikationen från Oracle Java 17 (2024) är Instant designad för maskinutbyte av tidsstämplar och är en analog till System.currentTimeMillis(), men med nanosekunders precision.
Huvudpunkter
Instant — är en klass som modellerar en enskild punkt på tidslinjen. Dess interna representation består av två fält: long seconds (antal sekunder från 1970-01-01T00:00:00Z) och int nanos (nanosekunder inom den aktuella sekunden, från 0 till 999999999).
Intervallet för Instant-värden — från -31557014167219200 till 31556889864403199 sekunder från epoken, vilket täcker ungefär 292 miljoner år i båda riktningarna. Detta är tillräckligt för alla praktiska uppgifter, inklusive astronomiska beräkningar.
Enligt Baeldung (2024) är Instant en bro mellan mänskligt läsbara typer (LocalDateTime, ZonedDateTime) och maskinformat (timestamp i millisekunder). Instant används för loggning, cachning, synkronisering och alla uppgifter där det absoluta tidsögonblicket är viktigt.
Klassen implementerar gränssnitten Comparable (för att jämföra ögonblick) och Temporal (för användning i det allmänna java-time-API:et). Instant är oföränderlig — alla metoder returnerar ett nytt objekt.
Före Java 8 användes java.util.Date och System.currentTimeMillis() för att arbeta med tidsögonblick. Båda metoderna har nackdelar. Date är föränderlig, inte trådsäker, lagrar tid i millisekunder från epoken, men metodnamnen är föråldrade (getYear() returnerar 116 för 2016).
Long (enkel timestamp) är snabb och kompakt, men har inget inbyggt stöd för nanosekunder, visas inte i läsbar form och kräver manuell tolkning vid felsökning. Long-metoden skiljer inte heller på datatyper — utvecklaren kan skicka ett felaktigt värde.
Instant löser alla dessa problem. Den är oföränderlig, innehåller explicit information om precision (sekunder + nanosekunder), serialiseras till ISO-8601-format "2026-07-21T15:00:00Z" och har ett rikt API för konverteringar. Enligt SonarSource (2024) är Instant den rekommenderade ersättningen för Date i alla nya projekt.
Det aktuella ögonblicket erhålls via Instant.now(). Till skillnad från LocalDateTime.now() returnerar Instant.now() alltid tiden i UTC, oavsett enhetens tidszon. Detta gör den idealisk för servertidsstämplar.
Från befintliga värden: Instant.ofEpochSecond(long epochSecond) — från sekunder från epoken, Instant.ofEpochMilli(long epochMilli) — från millisekunder, Instant.parse(CharSequence) — från en ISO-8601-sträng ("2026-07-21T15:00:00Z").
För läsning används getEpochSecond() — antal sekunder från epoken, toEpochMilli() — antal millisekunder, getNano() — nanosekunder. Metoden toString() returnerar en sträng i ISO-8601-format.
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()
Instant konverteras till ZonedDateTime via atZone(ZoneId). Till exempel kommer Instant.now().atZone(ZoneId.of("Europe/Moscow")) att returnera ZonedDateTime för Moskva. Utan zon är konvertering omöjlig — Instant innehåller ingen kalenderinformation.
Till LocalDateTime konverteras Instant via atZone(ZoneId).toLocalDateTime(). Denna metod är explicit och förlorar inte information. Omvänd konvertering — LocalDateTime.atZone(ZoneId).toInstant().
För kompatibilitet med java.util.Date: Date.from(instant) och date.toInstant(). Detta är en dubbelriktad konvertering som bevarar precisionen upp till millisekunder (Date stöder inte nanosekunder). För arbete med java.sql.Timestamp används Timestamp.from(instant) med stöd för nanosekunder.
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()
Den viktigaste egenskapen hos Instant — den är helt oberoende av tidszoner. Instant.now() returnerar samma resultat på vilken enhet som helst, var som helst i världen. Detta uppnås genom att tiden är fixerad i UTC.
Tidszon behövs endast för att visa Instant för människor. För detta används atZone(ZoneId). ZoneId.systemDefault() returnerar enhetens tidszon som är inställd i operativsystemet. ZoneOffset.UTC — konstant för UTC.
I distribuerade system rekommenderas att lagra och överföra alla tidsstämplar i Instant (eller OffsetDateTime med ZoneOffset.UTC). Konvertering till lokal tid utförs endast på klientsidan före visning för användaren. Detta förhindrar förvirring med tidszoner.
I distribuerade Android-applikationer är tidssynkronisering avgörande för korrekt funktion av cachning, notifieringar och samarbetsredigering. Instant — det naturliga valet för denna uppgift tack vare kopplingen till UTC.
Vid jämförelse av tidsstämplar från olika enheter måste man beakta att systemklockor kan skilja sig åt. Det rekommenderas att använda servertid som referens. Servern returnerar Instant i UTC, klienten jämför med lokal Instant endast för relativa beräkningar.
För att beräkna skillnaden mellan två ögonblick används Duration.between(Instant start, Instant end). Denna metod returnerar Duration — en tidsperiod som kan konverteras till timmar, minuter, sekunder. Metoderna isAfter() och isBefore() gör det möjligt att jämföra ögonblick.
fun isCacheExpired(
cachedAt: Instant,
ttlMinutes: Long
): Boolean {
val elapsed = Duration.between(cachedAt, Instant.now())
return elapsed.toMinutes() >= ttlMinutes
}
Det första exemplet — loggning av händelser med tidsstämpel. Instant lagras i Room-databasen och skickas till servern. Tidsstämpeln loggas i UTC för entydig tolkning.
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) }
}
}
Det andra exemplet — bestämning av tid som förflutit sedan en händelse. Vi använder Duration.between för att visa "5 minuter sedan", "2 timmar sedan" — ett format som är vanligt i meddelandeprogram och sociala medier.
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"
}
}
Det tredje exemplet — synkronisering av data mellan server och klient. Vi använder Instant för att spåra tiden för senaste uppdatering.
class SyncManager {
private var lastSyncAt: Instant? = null
fun sync() {
val syncStart = Instant.now()
// serverförfrågan med lastSyncAt
lastSyncAt = syncStart
}
fun shouldSync(intervalMinutes: Long): Boolean {
val last = lastSyncAt ?: return true
return Duration.between(last, Instant.now())
.toMinutes() >= intervalMinutes
}
}
Det första misstaget — att använda Instant.now().toString() för visning för användaren. Instant visas i UTC-format "2026-07-21T15:00:00Z", vilket är oläsligt för människor. Konvertera alltid Instant via atZone() till lokal tidszon före visning.
Det andra misstaget — förlust av nanosekunder vid konvertering till java.util.Date. Date stöder endast millisekunder. Om Instant har nanosekunder går de förlorade vid Date.from(instant). Använd Instant.truncatedTo(ChronoUnit.MILLIS) för explicit angivelse av precision.
Det tredje misstaget — sammanblandning av toEpochMilli() och getEpochSecond(). toEpochMilli() returnerar antalet millisekunder från epoken (long), medan getEpochSecond() returnerar antalet sekunder (long). Att blanda ihop dessa metoder kan leda till ett 1000 gångers fel.
Det fjärde misstaget — antagandet att Instant.now() är synkroniserad på alla enheter. Systemklockor kan skilja sig med minuter och till och med timmar. För tidskritiska operationer (autentisering, betalningar) använd server Instant som källa till sanning.
Vanliga frågor
System.currentTimeMillis() returnerar en long — antalet millisekunder från epoken utan koppling till tidszon. Instant erbjuder samma funktionalitet, men med nanosekunders precision och ett rikt API för konverteringar, jämförelser och kompatibilitet med java.time.
Room stöder inte Instant direkt. Använd en TypeConverter som konverterar Instant till Long (toEpochMilli) och tillbaka (Instant.ofEpochMilli). För nanosekunders precision, spara två fält: epok-sekunder och nanosekunder.
Ja, Instant är oföränderlig och implementerar korrekt equals() och hashCode(). Två Instant med samma värde kommer att vara lika. Detta gör den till en pålitlig nyckel för HashMap och andra samlingar, till skillnad från den föränderliga java.util.Date.
Använd Duration.between(start, end) för att få Duration eller ChronoUnit.SECONDS.between(start, end) för skillnaden i sekunder (long). Duration tillhandahåller metoderna toMinutes(), toHours(), toDays() och toNanos().
Instant är designad som en absolut punkt på tidslinjen. Utan angivelse av tidszon eller UTC är tolkning omöjlig, eftersom Instant inte innehåller kalenderinformation. Suffixet "Z" betecknar noll-offset (UTC) och är obligatoriskt för ISO-8601-format.
Sammanfattning
Vi utvecklar en mobil applikation nyckelfärdigt
IT Sectr skapar iOS- och Android-applikationer för startups och företag sedan 2017. Vi ger dig råd och föreslår den bästa lösningen.
Läs också