Instant — kelas immutable dari paket java.time yang merepresentasikan titik pada garis waktu dalam UTC dengan presisi nanodetik. Tidak seperti LocalDateTime, Instant tidak berisi tanggal dan waktu dalam format yang dapat dibaca manusia — ini adalah representasi mesin dari suatu momen. Menurut spesifikasi Oracle Java 17 (2024), Instant dirancang untuk pertukaran stempel waktu mesin dan merupakan analog dari System.currentTimeMillis(), tetapi dengan presisi nanodetik.
Poin Utama
Instant — adalah kelas yang memodelkan satu titik pada garis waktu. Representasi internalnya terdiri dari dua bidang: long seconds (jumlah detik dari 1970-01-01T00:00:00Z) dan int nanos (nanodetik dalam detik saat ini, dari 0 hingga 999999999).
Rentang nilai Instant — dari -31557014167219200 hingga 31556889864403199 detik dari epoch, yang mencakup sekitar 292 juta tahun di kedua arah. Ini cukup untuk semua tugas praktis, termasuk perhitungan astronomi.
Menurut Baeldung (2024), Instant adalah jembatan antara tipe yang dapat dibaca manusia (LocalDateTime, ZonedDateTime) dan format mesin (timestamp dalam milidetik). Instant digunakan untuk logging, caching, sinkronisasi, dan semua tugas di mana momen absolut waktu penting.
Kelas mengimplementasikan antarmuka Comparable (untuk membandingkan momen) dan Temporal (untuk digunakan dalam API java.time umum). Instant bersifat immutable — semua metode mengembalikan objek baru.
Sebelum Java 8, untuk bekerja dengan momen waktu digunakan java.util.Date dan System.currentTimeMillis(). Kedua pendekatan memiliki kekurangan. Date bersifat mutable, tidak thread-safe, menyimpan waktu dalam milidetik dari epoch, tetapi nama metodenya sudah usang (getYear() mengembalikan 116 untuk 2016).
Long (timestamp sederhana) cepat dan ringkas, tetapi tidak memiliki dukungan bawaan untuk nanodetik, tidak ditampilkan dalam bentuk yang dapat dibaca, dan memerlukan parsing manual saat debugging. Pendekatan Long juga tidak membedakan tipe data — pengembang dapat mengirimkan nilai yang salah.
Instant menyelesaikan semua masalah ini. Ia immutable, berisi informasi eksplisit tentang presisi (detik + nanodetik), diserialisasi ke format ISO-8601 "2026-07-21T15:00:00Z" dan memiliki API yang kaya untuk konversi. Menurut SonarSource (2024), Instant adalah pengganti yang direkomendasikan untuk Date di semua proyek baru.
Momen saat ini diperoleh melalui Instant.now(). Tidak seperti LocalDateTime.now(), Instant.now() selalu mengembalikan waktu dalam UTC, mengabaikan zona waktu perangkat. Ini membuatnya ideal untuk stempel waktu server.
Dari nilai yang ada: Instant.ofEpochSecond(long epochSecond) — dari detik sejak epoch, Instant.ofEpochMilli(long epochMilli) — dari milidetik, Instant.parse(CharSequence) — dari string ISO-8601 ("2026-07-21T15:00:00Z").
Untuk membaca digunakan getEpochSecond() — jumlah detik dari epoch, toEpochMilli() — jumlah milidetik, getNano() — nanodetik. Metode toString() mengembalikan string dalam format 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 dikonversi ke ZonedDateTime melalui atZone(ZoneId). Misalnya, Instant.now().atZone(ZoneId.of("Europe/Moscow")) akan mengembalikan ZonedDateTime untuk Moskow. Tanpa zona, konversi tidak mungkin — Instant tidak berisi informasi kalender.
Ke LocalDateTime Instant dikonversi melalui atZone(ZoneId).toLocalDateTime(). Cara ini eksplisit dan tidak kehilangan informasi. Konversi sebaliknya — LocalDateTime.atZone(ZoneId).toInstant().
Untuk kompatibilitas dengan java.util.Date: Date.from(instant) dan date.toInstant(). Ini adalah konversi dua arah yang mempertahankan presisi hingga milidetik (Date tidak mendukung nanodetik). Untuk bekerja dengan java.sql.Timestamp digunakan Timestamp.from(instant) dengan dukungan nanodetik.
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()
Fitur utama Instant — ia sepenuhnya independen dari zona waktu. Instant.now() mengembalikan hasil yang sama di perangkat mana pun di mana pun di dunia. Ini dicapai dengan menetapkan waktu dalam UTC.
Zona waktu hanya diperlukan untuk menampilkan Instant kepada manusia. Untuk ini digunakan atZone(ZoneId). ZoneId.systemDefault() mengembalikan zona waktu perangkat yang diatur di sistem operasi. ZoneOffset.UTC — konstanta untuk UTC.
Dalam sistem terdistribusi, disarankan untuk menyimpan dan mengirimkan semua stempel waktu dalam Instant (atau OffsetDateTime dengan ZoneOffset.UTC). Konversi ke waktu lokal dilakukan hanya di sisi klien sebelum ditampilkan kepada pengguna. Ini mencegah kebingungan dengan zona waktu.
Dalam aplikasi Android terdistribusi, sinkronisasi waktu sangat penting untuk berfungsinya caching, notifikasi, dan pengeditan bersama. Instant — pilihan alami untuk tugas ini karena kaitannya dengan UTC.
Saat membandingkan stempel waktu dari perangkat yang berbeda, perlu dipertimbangkan bahwa jam sistem mungkin berbeda. Disarankan untuk menggunakan waktu server sebagai referensi. Server mengembalikan Instant dalam UTC, klien membandingkan dengan Instant lokal hanya untuk perhitungan relatif.
Untuk menghitung perbedaan antara dua momen digunakan Duration.between(Instant start, Instant end). Metode ini mengembalikan Duration — durasi yang dapat dikonversi ke jam, menit, detik. Metode isAfter() dan isBefore() memungkinkan membandingkan momen.
fun isCacheExpired(
cachedAt: Instant,
ttlMinutes: Long
): Boolean {
val elapsed = Duration.between(cachedAt, Instant.now())
return elapsed.toMinutes() >= ttlMinutes
}
Contoh pertama — pencatatan peristiwa dengan stempel waktu. Instant disimpan di database Room dan dikirim ke server. Stempel waktu dicatat dalam UTC untuk interpretasi yang unik.
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) }
}
}
Contoh kedua — menentukan waktu yang telah berlalu sejak suatu peristiwa. Kami menggunakan Duration.between untuk menampilkan "5 menit yang lalu", "2 jam yang lalu" — format yang umum di aplikasi perpesanan dan media sosial.
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"
}
}
Contoh ketiga — sinkronisasi data antara server dan klien. Kami menggunakan Instant untuk melacak waktu pembaruan terakhir.
class SyncManager {
private var lastSyncAt: Instant? = null
fun sync() {
val syncStart = Instant.now()
// permintaan server dengan lastSyncAt
lastSyncAt = syncStart
}
fun shouldSync(intervalMinutes: Long): Boolean {
val last = lastSyncAt ?: return true
return Duration.between(last, Instant.now())
.toMinutes() >= intervalMinutes
}
}
Kesalahan pertama — menggunakan Instant.now().toString() untuk ditampilkan kepada pengguna. Instant ditampilkan dalam format UTC "2026-07-21T15:00:00Z", yang tidak dapat dibaca manusia. Selalu konversikan Instant melalui atZone() ke zona waktu lokal sebelum ditampilkan.
Kesalahan kedua — kehilangan nanodetik saat konversi ke java.util.Date. Date hanya mendukung milidetik. Jika Instant memiliki nanodetik, mereka akan hilang saat Date.from(instant). Gunakan Instant.truncatedTo(ChronoUnit.MILLIS) untuk menentukan presisi secara eksplisit.
Kesalahan ketiga — kebingungan antara toEpochMilli() dan getEpochSecond(). toEpochMilli() mengembalikan jumlah milidetik dari epoch (long), sedangkan getEpochSecond() mengembalikan jumlah detik (long). Mencampuradukkan metode ini dapat menyebabkan kesalahan 1000 kali lipat.
Kesalahan keempat — asumsi bahwa Instant.now() disinkronkan di semua perangkat. Jam sistem dapat berbeda menit dan bahkan jam. Untuk operasi yang sensitif terhadap waktu (otentikasi, pembayaran) gunakan Instant server sebagai sumber kebenaran.
Pertanyaan yang Sering Diajukan
System.currentTimeMillis() mengembalikan long — jumlah milidetik dari epoch tanpa kaitan dengan zona waktu. Instant menyediakan fungsionalitas yang sama, tetapi dengan presisi nanodetik dan API yang kaya untuk konversi, perbandingan, dan kompatibilitas dengan java.time.
Room tidak mendukung Instant secara langsung. Gunakan TypeConverter yang mengonversi Instant ke Long (toEpochMilli) dan sebaliknya (Instant.ofEpochMilli). Untuk presisi nanodetik, simpan dua bidang: epoch-detik dan nanodetik.
Ya, Instant bersifat immutable dan mengimplementasikan equals() dan hashCode() dengan benar. Dua Instant dengan nilai yang sama akan sama. Ini menjadikannya kunci yang andal untuk HashMap dan koleksi lainnya, tidak seperti java.util.Date yang mutable.
Gunakan Duration.between(start, end) untuk mendapatkan Duration atau ChronoUnit.SECONDS.between(start, end) untuk perbedaan dalam detik (long). Duration menyediakan metode toMinutes(), toHours(), toDays() dan toNanos().
Instant dirancang sebagai titik absolut pada garis waktu. Tanpa menentukan zona waktu atau UTC, parsing tidak mungkin, karena Instant tidak berisi informasi kalender. Akhiran "Z" menunjukkan offset nol (UTC) dan wajib untuk format ISO-8601.
Ringkasan
Kami akan mengembangkan aplikasi seluler turnkey
IT Sectr membuat aplikasi iOS dan Android untuk startup dan bisnis sejak 2017. Kami akan memberi saran dan mengusulkan solusi terbaik.
Baca juga