Instant — java.time paketinden, UTC'de nanosaniye hassasiyetiyle zaman çizelgesinde bir noktayı temsil eden değişmez bir sınıf. LocalDateTime'in aksine, Instant insan tarafından okunabilir biçimde tarih ve saat içermez — bir anın makine temsilidir. Oracle Java 17 (2024) spesifikasyonuna göre Instant, zaman damgalarının makine değişimi için tasarlanmıştır ve System.currentTimeMillis()'in bir benzeridir, ancak nanosaniye hassasiyetine sahiptir.
Önemli Noktalar
Instant, zaman çizelgesinde tek bir noktayı modelleyen bir sınıftır. İç temsili iki alandan oluşur: long seconds (1970-01-01T00:00:00Z'den itibaren saniye sayısı) ve int nanos (geçerli saniye içindeki nanosaniyeler, 0 ile 999999999 arası).
Instant değerlerinin aralığı, çağdan itibaren -31557014167219200 ile 31556889864403199 saniye arasındadır ve her iki yönde yaklaşık 292 milyon yılı kapsar. Bu, astronomik hesaplamalar dahil her türlü pratik görev için yeterlidir.
Baeldung (2024)'e göre Instant, insan tarafından okunabilir türler (LocalDateTime, ZonedDateTime) ile makine biçimleri (milisaniye cinsinden zaman damgası) arasında bir köprüdür. Instant, günlükleme, önbellekleme, senkronizasyon ve zaman içinde mutlak bir anın önemli olduğu tüm görevler için kullanılır.
Sınıf, Comparable (anları karşılaştırmak için) ve Temporal (ortak java.time API'sinde kullanım için) arabirimlerini uygular. Instant değişmezdir — tüm yöntemler yeni bir nesne döndürür.
Java 8'den önce, zaman anlarıyla çalışmak için java.util.Date ve System.currentTimeMillis() kullanılıyordu. Her iki yaklaşımın da dezavantajları vardır. Date değiştirilebilir, iş parçacığı güvenli değildir, çağdan itibaren milisaniye cinsinden zamanı depolar, ancak yöntem adları eskimiştir (getYear(), 2016 için 116 döndürür).
Long (basit bir zaman damgası) hızlı ve kompakttır, ancak nanosaniyeler için yerleşik desteği yoktur, okunabilir bir biçimde görüntülenmez ve hata ayıklama sırasında manuel ayrıştırma gerektirir. Long yaklaşımı ayrıca veri türlerini ayırt etmez — bir geliştirici yanlış bir değer iletebilir.
Instant tüm bu sorunları çözer. Değişmezdir, açık hassasiyet bilgisi (saniye + nanosaniye) içerir, ISO-8601 biçimine (“2026-07-21T15:00:00Z”) serileştirilir ve dönüşümler için zengin bir API'ye sahiptir. SonarSource (2024)'e göre Instant, tüm yeni projelerde Date'in önerilen yerine geçendir.
Geçerli an Instant.now() ile elde edilir. LocalDateTime.now()'ın aksine, Instant.now() cihazın saat dilimini yok sayarak her zaman UTC'deki saati döndürür. Bu onu sunucu zaman damgaları için ideal kılar.
Mevcut değerlerden: Instant.ofEpochSecond(long epochSecond) — çağdan itibaren saniyelerden, Instant.ofEpochMilli(long epochMilli) — milisaniyelerden, Instant.parse(CharSequence) — ISO-8601 dizesinden (“2026-07-21T15:00:00Z”).
Okuma için: getEpochSecond() — çağdan itibaren saniye sayısı, toEpochMilli() — milisaniye sayısı, getNano() — nanosaniyeler. toString() yöntemi ISO-8601 biçiminde bir dize döndürür.
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, atZone(ZoneId) aracılığıyla ZonedDateTime'e dönüştürülür. Örneğin, Instant.now().atZone(ZoneId.of(“Europe/Moscow”)) Moskova için bir ZonedDateTime döndürür. Bir saat dilimi olmadan dönüştürme imkansızdır — Instant takvim bilgisi içermez.
Instant'ı LocalDateTime'e dönüştürmek için: atZone(ZoneId).toLocalDateTime(). Bu yaklaşım açıktır ve bilgi kaybetmez. Ters dönüştürme: LocalDateTime.atZone(ZoneId).toInstant().
java.util.Date ile uyumluluk için: Date.from(instant) ve date.toInstant(). Bu, milisaniyeye kadar hassasiyeti koruyan çift yönlü bir dönüştürmedir (Date nanosaniyeleri desteklemez). java.sql.Timestamp için, nanosaniye desteğiyle Timestamp.from(instant) kullanın.
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'ın temel özelliği, saat dilimlerinden tamamen bağımsız olmasıdır. Instant.now() dünyanın herhangi bir yerindeki herhangi bir cihazda aynı sonucu döndürür. Bu, zamanı UTC'ye sabitleyerek elde edilir.
Bir saat dilimi yalnızca Instant'ı bir insana göstermek için gereklidir. Bunun için atZone(ZoneId) kullanılır. ZoneId.systemDefault(), işletim sisteminde ayarlanan cihazın saat dilimini döndürür. ZoneOffset.UTC, UTC için sabittir.
Dağıtık sistemlerde, tüm zaman damgalarını Instant (veya ZoneOffset.UTC ile OffsetDateTime) olarak saklamanız ve iletmeniz önerilir. Yerel saate dönüştürme, yalnızca kullanıcıya göstermeden önce istemcide gerçekleştirilir. Bu, saat dilimi karışıklığını önler.
Dağıtık Android uygulamalarında, doğru önbellekleme, bildirimler ve işbirlikçi düzenleme için zaman senkronizasyonu kritiktir. Instant, UTC'ye sabitlenmesi sayesinde bu görev için doğal seçimdir.
Farklı cihazlardan zaman damgalarını karşılaştırırken, sistem saatlerinin farklı olabileceğini hesaba katmak gerekir. Referans olarak sunucu saatinin kullanılması önerilir. Sunucu UTC'de Instant döndürür ve istemci, yalnızca göreceli hesaplamalar için yerel Instant ile karşılaştırır.
İki an arasındaki farkı hesaplamak için Duration.between(Instant start, Instant end) kullanın. Bu yöntem, saat, dakika, saniyeye dönüştürülebilen bir Duration döndürür. isAfter() ve isBefore() yöntemleri anları karşılaştırmaya olanak tanır.
fun isCacheExpired(
cachedAt: Instant,
ttlMinutes: Long
): Boolean {
val elapsed = Duration.between(cachedAt, Instant.now())
return elapsed.toMinutes() >= ttlMinutes
}
İlk örnek, bir zaman damgasıyla olayları günlüklemedir. Instant Room veritabanına kaydedilir ve sunucuya gönderilir. Zaman damgası, net yorumlama için UTC'de günlüklenir.
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) }
}
}
İkinci örnek, bir olaydan bu yana geçen süreyi belirlemektir. “5 dakika önce”, “2 saat önce” göstermek için Duration.between kullanırız — mesajlaşma uygulamalarında ve sosyal ağlarda yaygın bir biçim.
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"
}
}
Üçüncü örnek, sunucu ve istemci arasında veri senkronizasyonudur. Son güncelleme zamanını izlemek için Instant kullanırız.
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
}
}
İlk hata, kullanıcıya göstermek için Instant.now().toString() kullanmaktır. Instant, UTC biçiminde (“2026-07-21T15:00:00Z”) çıktı verir ve bu insanlar için okunamaz. Görüntülemeden önce Instant'ı her zaman atZone() ile yerel saat dilimine dönüştürün.
İkinci hata, java.util.Date'e dönüştürürken nanosaniyeleri kaybetmektir. Date yalnızca milisaniyeleri destekler. Instant'da nanosaniyeler varsa, Date.from(instant)'da atılırlar. Hassasiyeti açıkça belirtmek için Instant.truncatedTo(ChronoUnit.MILLIS) kullanın.
Üçüncü hata, toEpochMilli() ve getEpochSecond() arasında karışıklıktır. toEpochMilli() çağdan itibaren milisaniye sayısını (long), getEpochSecond() ise saniye sayısını (long) döndürür. Bu yöntemleri karıştırmak 1000 kat hata oluşmasına neden olabilir.
Dördüncü hata, Instant.now()'ın tüm cihazlarda senkronize olduğunu varsaymaktır. Sistem saatleri dakikalar hatta saatler fark edebilir. Zamana duyarlı işlemler (kimlik doğrulama, ödemeler) için gerçeğin kaynağı olarak sunucu Instant'ını kullanın.
Sıkça Sorulan Sorular
System.currentTimeMillis() bir long döndürür — saat dilimi bağlaması olmadan çağdan itibaren milisaniye sayısı. Instant aynı işlevselliği sağlar ancak nanosaniye hassasiyeti ve dönüşümler, karşılaştırmalar ve java.time ile uyumluluk için zengin bir API ile birlikte sunar.
Room, Instant'ı doğrudan desteklemez. Instant'ı Long'a (toEpochMilli) ve geriye (Instant.ofEpochMilli) dönüştüren bir TypeConverter kullanın. Nanosaniye hassasiyeti için iki alan kaydedin: çağ-saniye ve nanosaniye.
Evet, Instant değişmezdir ve equals() ile hashCode()'u doğru şekilde uygular. Aynı değere sahip iki Instant eşit olacaktır. Bu, değiştirilebilir java.util.Date'in aksine onu HashMap ve diğer koleksiyonlar için güvenilir bir anahtar yapar.
Bir Duration almak için Duration.between(start, end) veya saniye (long) cinsinden fark için ChronoUnit.SECONDS.between(start, end) kullanın. Duration, toMinutes(), toHours(), toDays() ve toNanos() yöntemlerini sağlar.
Instant, zaman çizelgesinde mutlak bir nokta olarak tasarlanmıştır. Bir saat dilimi veya UTC belirtmeden ayrıştırma imkansızdır çünkü Instant takvim bilgisi içermez. “Z” soneki sıfır ofseti (UTC) belirtir ve ISO-8601 biçimi için zorunludur.
Özet
Anahtar teslim bir mobil uygulama geliştireceğiz
IT Sectr, 2017'den beri girişimler ve işletmeler için iOS ve Android uygulamaları oluşturmaktadır. Size danışmanlık yapacak ve en iyi çözümü önereceğiz.
Ayrıca okuyun