Instant — непроменљива класа из пакета java.time, која представља тачку на временској скали у UTC са прецизношћу до наносекунде. За разлику од LocalDateTime, Instant не садржи датум и време у формату читљивом за човека — то је машинска репрезентација тренутка. Према спецификацији Oracle Java 17 (2024), Instant је пројектован за машинску размену временских ознака и аналоган је System.currentTimeMillis(), али са наносекундном прецизношћу.
Главно
Instant — је класа која моделује појединачну тачку на временској скали. Њена унутрашња репрезентација се састоји од два поља: long seconds (број секунди од 1970-01-01T00:00:00Z) и int nanos (наносекунде у оквиру текуће секунде, од 0 до 999999999).
Опсег вредности Instant-а — од -31557014167219200 до 31556889864403199 секунди од епохе, што покрива приближно 292 милиона година у оба смера. Ово је довољно за било које практичне задатке, укључујући астрономска израчунавања.
Према Baeldung (2024), Instant је мост између типова читљивих за човека (LocalDateTime, ZonedDateTime) и машинских формата (timestamp у милисекундама). Instant се користи за логовање, кеширање, синхронизацију и све задатке где је апсолутни тренутак времена важан.
Класа имплементира интерфејсе Comparable (за поређење тренутака) и Temporal (за коришћење у општем API-ју java.time). Instant је непроменљив — све методе враћају нови објекат.
Пре Java 8 за рад са тренуцима времена коришћени су java.util.Date и System.currentTimeMillis(). Оба приступа имају недостатке. Date је променљив, није thread-safe, чува време у милисекундама од епохе, али називи метода су застарели (getYear() враћа 116 за 2016).
Long (једноставан timestamp) је брз и компактан, али нема уграђену подршку за наносекунде, не приказује се у читљивом облику и захтева ручно парсирање при отклањању грешака. Long приступ такође не разликује тип података — програмер може пренети нетачну вредност.
Instant решава све ове проблеме. Непроменљив је, садржи експлицитну информацију о прецизности (секунде + наносекунде), серијализује се у ISO-8601 формат „2026-07-21T15:00:00Z” и има богат API за конверзије. Према SonarSource (2024), Instant је препоручена замена за Date у свим новим пројектима.
Тренутни тренутак се добија путем Instant.now(). За разлику од LocalDateTime.now(), Instant.now() увек враћа време у UTC, игноришући временску зону уређаја. То га чини идеалним за серверске временске ознаке.
Из постојећих вредности: Instant.ofEpochSecond(long epochSecond) — из секунди од епохе, Instant.ofEpochMilli(long epochMilli) — из милисекунди, Instant.parse(CharSequence) — из ниске ISO-8601 („2026-07-21T15:00:00Z”).
За читање се користи getEpochSecond() — број секунди од епохе, toEpochMilli() — број милисекунди, getNano() — наносекунде. Метода toString() враћа ниску у формату ISO-8601.
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 се претвара у ZonedDateTime путем atZone(ZoneId). На пример, Instant.now().atZone(ZoneId.of("Europe/Moscow")) ће вратити ZonedDateTime за Москву. Без зоне конверзија је немогућа — Instant не садржи календарске информације.
У LocalDateTime Instant се претвара путем atZone(ZoneId).toLocalDateTime(). Овај начин је експлицитан и не губи информације. Обрнута конверзија — LocalDateTime.atZone(ZoneId).toInstant().
За компатибилност са java.util.Date: Date.from(instant) и date.toInstant(). Ово је двосмерна конверзија која чува прецизност до милисекунди (Date не подржава наносекунде). За рад са java.sql.Timestamp користи се Timestamp.from(instant) са подршком за наносекунде.
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-а — потпуно је независан од временских зона. Instant.now() враћа исти резултат на било ком уређају у било ком делу света. То се постиже фиксирањем времена у UTC.
Временска зона је потребна само за приказ Instant-а човеку. За то се користи atZone(ZoneId). ZoneId.systemDefault() враћа временску зону уређаја подешену у оперативном систему. ZoneOffset.UTC — константа за UTC.
У дистрибуираним системима препоручује се чување и пренос свих временских ознака у Instant-у (или OffsetDateTime са ZoneOffset.UTC). Конверзија у локално време се врши само на клијенту пре приказа кориснику. Ово спречава забуну са временским зонама.
У дистрибуираним Android апликацијама синхронизација времена је критична за исправан рад кеширања, обавештења и заједничког уређивања. Instant — природни избор за овај задатак захваљујући вези са UTC.
При поређењу временских ознака са различитих уређаја треба узети у обзир да системски сатови могу одступати. Препоручује се коришћење серверског времена као референтног. Сервер враћа Instant у UTC, клијент упоређује са локалним Instant-ом само за релативна израчунавања.
За израчунавање разлике између два тренутка користи се Duration.between(Instant start, Instant end). Ова метода враћа Duration — трајање које се може конвертовати у сате, минуте, секунде. Методе isAfter() и isBefore() омогућавају поређење тренутака.
fun isCacheExpired(
cachedAt: Instant,
ttlMinutes: Long
): Boolean {
val elapsed = Duration.between(cachedAt, Instant.now())
return elapsed.toMinutes() >= ttlMinutes
}
Први пример — евидентирање догађаја са временском ознаком. Instant се чува у бази података Room и шаље на сервер. Временска ознака се логује у UTC за једнозначну интерпретацију.
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) }
}
}
Други пример — одређивање времена протеклог од догађаја. Користимо Duration.between за приказ „пре 5 минута”, „пре 2 сата” — формата распространеног у месенџерима и друштвеним мрежама.
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"
}
}
Трећи пример — синхронизација података између сервера и клијента. Користимо Instant за праћење времена последњег ажурирања.
class SyncManager {
private var lastSyncAt: Instant? = null
fun sync() {
val syncStart = Instant.now()
// серверски захтев са lastSyncAt
lastSyncAt = syncStart
}
fun shouldSync(intervalMinutes: Long): Boolean {
val last = lastSyncAt ?: return true
return Duration.between(last, Instant.now())
.toMinutes() >= intervalMinutes
}
}
Прва грешка — коришћење Instant.now().toString() за приказ кориснику. Instant се приказује у UTC формату „2026-07-21T15:00:00Z”, који је нечитак за човека. Увек претварајте Instant путем atZone() у локалну временску зону пре приказа.
Друга грешка — губитак наносекунди при конверзији у java.util.Date. Date подржава само милисекунде. Ако Instant има наносекунде, оне ће бити изгубљене при Date.from(instant). Користите Instant.truncatedTo(ChronoUnit.MILLIS) за експлицитно навођење прецизности.
Трећа грешка — забуна између toEpochMilli() и getEpochSecond(). toEpochMilli() враћа број милисекунди од епохе (long), а getEpochSecond() враћа број секунди (long). Мешање ових метода може довести до грешке од 1000 пута.
Четврта грешка — претпоставка да је Instant.now() синхронизован на свим уређајима. Системски сатови могу одступати за минуте, па чак и сате. За временски критичне операције (аутентификација, плаћања) користите серверски Instant као извор истине.
Често постављана питања
System.currentTimeMillis() враћа long — број милисекунди од епохе без повезаности са временском зоном. Instant пружа исту функционалност, али са наносекундном прецизношћу и богатим API-јем за конверзије, поређења и компатибилност са java.time.
Room не подржава Instant директно. Користите TypeConverter који претвара Instant у Long (toEpochMilli) и назад (Instant.ofEpochMilli). За наносекундну прецизност чувајте два поља: епоха-секунде и наносекунде.
Да, Instant је непроменљив и исправно имплементира equals() и hashCode(). Два Instant-а са истом вредношћу ће бити једнака. То га чини поузданим кључем за HashMap и друге колекције, за разлику од променљивог java.util.Date.
Користите Duration.between(start, end) за добијање Duration или ChronoUnit.SECONDS.between(start, end) за разлику у секундама (long). Duration пружа методе toMinutes(), toHours(), toDays() и toNanos().
Instant је пројектован као апсолутна тачка на временској скали. Без навођења временске зоне или UTC парсирање је немогуће, јер Instant не садржи календарске информације. Суфикс „Z” означава нулти помак (UTC) и обавезан је за ISO-8601 формат.
Резиме
Развићемо мобилну апликацију под кључ
IT Sectr креира iOS и Android апликације за стартапе и предузећа од 2017. године. Саветоваћемо вас и предложити најбоље решење.
Прочитајте такође