Instant: apa itu, stempel waktu dan penerapan dalam pengembangan

Penulis: IT Sectr Diterbitkan: 2026-07-13 Waktu membaca: 9 mnt

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 — momen waktu dalam UTC dengan presisi nanodetik, immutable dan thread-safe.
  • Menyimpan waktu sebagai jumlah detik dari epoch (1970-01-01T00:00:00Z) ditambah nanodetik.
  • Instant.now() mengembalikan momen saat ini dalam UTC terlepas dari zona waktu perangkat.
  • Untuk konversi ke format yang dapat dibaca manusia digunakan atZone(ZoneId), yang mengembalikan ZonedDateTime.
  • Instant — tipe yang lebih disukai untuk mengirimkan stempel waktu di API dan sistem terdistribusi.

Apa itu Instant?

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.

Instant vs Date vs Long

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.

Membuat dan Membaca Instant

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.

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

Konversi Instant ke Format Lain

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.

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 dan Zona Waktu

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.

Sinkronisasi Waktu melalui Instant

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.

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

Contoh Praktis di Android

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.

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

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.

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

Contoh ketiga — sinkronisasi data antara server dan klien. Kami menggunakan Instant untuk melacak waktu pembaruan terakhir.

kotlin
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 Umum

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

Apa perbedaan Instant dengan System.currentTimeMillis()?

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.

Bagaimana cara menyimpan Instant di Room Database?

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.

Bisakah Instant digunakan sebagai kunci di HashMap?

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.

Bagaimana cara mendapatkan perbedaan antara dua Instant?

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().

Mengapa Instant.parse() memerlukan akhiran Z atau offset?

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

  • Instant — kelas immutable untuk momen waktu absolut dalam UTC dengan presisi nanodetik, lebih disukai untuk stempel waktu di sistem terdistribusi.
  • Tidak seperti java.util.Date, Instant bersifat immutable, thread-safe dan memiliki presisi nanodetik. Tidak seperti Long — secara eksplisit diketik dan tidak memungkinkan kebingungan dengan nilai numerik lainnya.
  • Untuk ditampilkan kepada pengguna, Instant dikonversi melalui atZone(ZoneId) ke ZonedDateTime, jika tidak, waktu akan ditampilkan dalam UTC.
  • Untuk transmisi di API gunakan Instant.toString() (ISO-8601) atau toEpochMilli() untuk kompatibilitas dengan format lama.
  • Saat bekerja dengan Room, simpan Instant sebagai Long melalui TypeConverter dengan metode toEpochMilli().
  • Untuk menghitung waktu yang telah berlalu, gunakan Duration.between(), yang memproses nanodetik dengan benar.
  • Jangan mengandalkan sinkronisasi jam perangkat — untuk operasi kritis gunakan Instant server sebagai sumber kebenaran.

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.

Diskusikan proyek

Baca juga