LocalDate, LocalTime dan LocalDateTime: apa itu, bekerja dengan tanggal

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

LocalDate, LocalTime dan LocalDateTime — kelas utama dari paket java.time yang menyediakan pekerjaan dengan tanggal dan waktu tanpa terikat pada zona waktu. Menurut dokumentasi Oracle (Java 17, 2024), tipe-tipe ini dirancang sebagai immutable dan thread-safe, yang membuatnya aman untuk aplikasi multi-thread. Mereka tersedia di Android melalui desugaring mulai API 26, dan untuk versi yang lebih lama melalui pustaka ThreeTenABP.

Poin utama

  • LocalDate — kelas immutable untuk representasi tanggal (tahun, bulan, hari) tanpa waktu dan zona waktu.
  • LocalTime — kelas immutable untuk representasi waktu (jam, menit, detik, nanodetik) tanpa tanggal dan zona waktu.
  • LocalDateTime — kombinasi LocalDate dan LocalTime, menyimpan tanggal dan waktu tanpa terikat pada zona.
  • Ketiga kelas mendukung operasi aritmatika — penambahan dan pengurangan hari, bulan, jam melalui metode plus dan minus.
  • Di Android tipe-tipe ini tersedia melalui desugaring (API 26+) atau pustaka ThreeTenABP (API < 26).

Apa itu LocalDate, LocalTime dan LocalDateTime?

LocalDate — kelas yang merepresentasikan tanggal dalam format tahun-bulan-hari tanpa informasi tentang waktu dan zona waktu. Digunakan untuk menyimpan data seperti tanggal lahir, tanggal acara atau tanggal kedaluwarsa.

LocalDate menyimpan tahun dalam rentang -999999999 hingga +999999999, bulan dari 1 hingga 12 dan hari dalam bulan dengan mempertimbangkan tahun kabisat. Kelas ini sepenuhnya immutable — setiap operasi mengembalikan objek baru.

LocalTime merepresentasikan waktu dalam sehari: jam, menit, detik dan nanodetik. Presisi maksimum — hingga nanodetik. LocalTime tidak berisi informasi tentang tanggal dan zona waktu, yang membuatnya nyaman untuk menyimpan jam buka toko atau durasi proses.

LocalDateTime menggabungkan LocalDate dan LocalTime dalam satu objek. Ini adalah tipe yang paling sering digunakan ketika perlu menyimpan tanggal dan waktu, tetapi keterikatan pada zona waktu tidak diperlukan. Misalnya, tanggal dan waktu konser dalam format lokal.

Menurut Oracle Java Documentation (2024), ketiga kelas dirancang berdasarkan ide dari pustaka Joda-Time, tetapi dengan arsitektur yang ditingkatkan dan integrasi penuh ke dalam pustaka standar.

Bagaimana paket java.time terstruktur?

Paket java.time muncul di Java 8 sebagai pengganti kelas-kelas usang Date, Calendar dan SimpleDateFormat. Arsitekturnya dibangun di atas prinsip objek immutable dan antarmuka fluent.

Fitur utama — semua kelas utama adalah value-based. Ini berarti instance mereka dibandingkan berdasarkan nilai, bukan referensi, dan mereka tidak dapat diwariskan. Untuk membandingkan dua objek digunakan metode equals, bukan operator ==.

Paket ini dibagi menjadi beberapa kategori. Tipe tanpa zona waktu — LocalDate, LocalTime, LocalDateTime — digunakan untuk tanggal dan waktu lokal. Tipe dengan zona waktu — ZonedDateTime, OffsetDateTime, OffsetTime — menambahkan informasi tentang offset atau zona. Tipe sesaat — Instant — mewakili titik pada garis waktu dalam UTC.

Pembagian ini memecahkan masalah yang khas dari API lama: programmer tidak pernah tahu apakah objek Date berisi informasi tentang zona waktu atau tidak. Di java.time setiap tipe secara eksplisit mendeklarasikan semantiknya.

LocalDate: bekerja dengan tanggal

Kelas LocalDate menyediakan banyak metode untuk membuat, membaca dan memodifikasi tanggal. Tanggal saat ini dapat diperoleh melalui metode statis now(). Tanggal tertentu — melalui metode of(int year, int month, int dayOfMonth).

Untuk membaca komponen tanggal digunakan getter: getYear(), getMonthValue(), getDayOfMonth(), getDayOfWeek(), getDayOfYear(). Metode getMonth() mengembalikan enum Month, dan getDayOfWeek() — enum DayOfWeek.

LocalDate mendukung pemeriksaan tanggal. Metode isBefore(), isAfter() dan isEqual() memungkinkan membandingkan tanggal. Metode isLeapYear() memeriksa apakah tahun adalah tahun kabisat. Metode lengthOfMonth() mengembalikan jumlah hari dalam bulan, dan lengthOfYear() — dalam tahun.

Untuk modifikasi digunakan metode withYear(), withMonth(), withDayOfMonth(), yang mengembalikan objek baru dengan komponen yang diubah. Metode plusDays(), minusMonths() dan sejenisnya melakukan aritmatika tanggal.

LocalTime: bekerja dengan waktu

LocalTime mewakili waktu dalam sehari dengan presisi hingga nanodetik. Format standar — ISO-8601 (HH:mm:ss.nnnnnnnnn). Nilai minimum — 00:00, maksimum — 23:59:59.999999999.

Objek LocalTime dapat dibuat melalui now() untuk waktu saat ini, of(int hour, int minute), of(int hour, int minute, int second) atau of(int hour, int minute, int second, int nanoOfSecond). Metode parse(CharSequence text) mem-parse string dalam format ISO-8601.

Getter meliputi getHour(), getMinute(), getSecond(), getNano(). Metode toSecondOfDay() mengembalikan jumlah detik sejak awal hari, dan toNanoOfDay() — nanodetik. Ini nyaman untuk perhitungan durasi dalam satu hari.

LocalTime mendukung operasi perbandingan dan modifikasi yang sama dengan LocalDate: plusHours(), minusMinutes(), withHour(), withMinute(). Metode isBefore() dan isAfter() bekerja dengan mempertimbangkan siklus waktu dalam sehari.

LocalDateTime: kombinasi tanggal dan waktu

LocalDateTime menggabungkan kemampuan LocalDate dan LocalTime dalam satu kelas. Menyimpan tanggal dan waktu, tetapi tanpa zona waktu. Ini adalah tipe lokal yang paling fleksibel, tetapi memerlukan kehati-hatian saat digunakan dalam sistem terdistribusi.

LocalDateTime dapat dibuat melalui metode statis now(), of(LocalDate date, LocalTime time), of(int year, Month month, int dayOfMonth, int hour, int minute) dan kelebihan muatannya. Juga dapat menggabungkan LocalDate dan LocalTime melalui metode atTime().

LocalDateTime menyediakan akses ke semua bidang tanggal dan waktu melalui getter yang sesuai: toLocalDate() dan toLocalTime() mengembalikan komponen terpisah. Metode truncatedTo(TemporalUnit unit) memungkinkan pembulatan waktu ke presisi tertentu — misalnya, hingga menit.

Untuk konversi ke zona waktu digunakan metode atZone(ZoneId zone), yang mengembalikan ZonedDateTime. Ini adalah satu-satunya cara untuk menambahkan zona waktu ke LocalDateTime.

Bagaimana membuat objek tanggal dan waktu?

Ketiga kelas menggunakan pola pembuatan seragam melalui metode pabrik statis. Konstruktor kelas dinyatakan sebagai private — objek tidak dapat dibuat langsung melalui new.

Cara utama pembuatan:

  • now() — tanggal/waktu saat ini dari jam sistem
  • of(...) — dari komponen (tahun, bulan, hari, dll.)
  • parse(String) — dari string dalam format ISO-8601
  • from(TemporalAccessor) — dari objek temporal lainnya

Metode of memiliki banyak kelebihan muatan. Untuk LocalDate diperlukan tahun, bulan dan hari. Untuk LocalTime — jam dan menit (opsional detik dan nanodetik). Untuk LocalDateTime — tahun, bulan, hari, jam, menit. Bulan dapat diberikan sebagai int (1-12) atau sebagai enum Month.

kotlin
val today = LocalDate.now()
val specificDate = LocalDate.of(2026, Month.JULY, 21)
val parsedDate = LocalDate.parse("2026-07-21")

val currentTime = LocalTime.now()
val lunchTime = LocalTime.of(13, 30, 0)
val parsedTime = LocalTime.parse("13:30:00")

val now = LocalDateTime.now()
val meeting = LocalDateTime.of(2026, 7, 21, 15, 0)

Konversi antar tipe

Kelas java.time dirancang untuk konversi yang mudah satu sama lain. LocalDate dapat dikonversi ke LocalDateTime melalui metode atTime(LocalTime) atau atStartOfDay(). LocalTime — melalui atDate(LocalDate).

LocalDateTime dapat dikonversi kembali ke LocalDate melalui toLocalDate() dan ke LocalTime melalui toLocalTime(). Untuk konversi ke ZonedDateTime digunakan metode atZone(ZoneId).

Konversi ke java.util.Date (untuk kompatibilitas dengan kode lama) memerlukan langkah perantara melalui Instant dan zona waktu. Menurut Baeldung (2024), operasi ini dilakukan melalui Date.from(instant).

kotlin
val date = LocalDate.of(2026, 7, 21)
val dateTime = date.atTime(LocalTime.of(10, 30))

val time = LocalTime.of(14, 0)
val dateTimeFromTime = time.atDate(date)

val extractedDate = dateTime.toLocalDate()
val extractedTime = dateTime.toLocalTime()

val zoned = dateTime.atZone(ZoneId.of("Europe/Moscow"))

Format dan parsing

Untuk format dan parsing digunakan kelas DateTimeFormatter. Ini menyediakan format yang telah ditentukan melalui konstanta (ISO_LOCAL_DATE, ISO_LOCAL_TIME, ISO_LOCAL_DATE_TIME) dan kemampuan untuk membuat format sendiri melalui pola.

Pola format menggunakan simbol: yyyy — tahun, MM — bulan (dua digit), dd — hari, HH — jam (0-23), mm — menit, ss — detik. Metode format() dipanggil pada objek tanggal-waktu atau melalui DateTimeFormatter.

DateTimeFormatter juga mendukung lokalisasi melalui metode statis ofLocalizedDate(FormatStyle), ofLocalizedTime(FormatStyle) dan ofLocalizedDateTime(FormatStyle). Gaya yang tersedia adalah SHORT, MEDIUM, LONG dan FULL.

kotlin
val formatter = DateTimeFormatter.ofPattern("dd.MM.yyyy HH:mm")
val formatted = LocalDateTime.now().format(formatter)

val parsed = LocalDate.parse(
    "21.07.2026",
    DateTimeFormatter.ofPattern("dd.MM.yyyy")
)

Perbandingan objek tanggal-waktu

Ketiga kelas mengimplementasikan antarmuka Comparable, yang memungkinkan perbandingan alami. Metode compareTo() mengembalikan angka negatif, nol atau positif tergantung urutan. Metode isBefore(), isAfter() dan isEqual() mengembalikan boolean.

Untuk LocalDate perbandingan dilakukan secara kronologis — tanggal lebih awal lebih kecil. Untuk LocalTime — menurut waktu dalam sehari. Untuk LocalDateTime — pertama berdasarkan tanggal, kemudian berdasarkan waktu. Semua perbandingan dengan benar mempertimbangkan tahun kabisat dan jumlah hari dalam bulan.

Perbedaan penting dari API lama: equals() untuk LocalDate, LocalTime dan LocalDateTime membandingkan nilai, bukan referensi. Ini berarti dua objek dengan bidang yang sama akan sama, bahkan jika mereka adalah instance yang berbeda.

kotlin
val d1 = LocalDate.of(2026, 7, 21)
val d2 = LocalDate.of(2026, 12, 25)

if (d1.isBefore(d2)) {
    Log.d("Tanggal", "d1 sebelum d2")
}

val sortedDates = listOf(d2, d1).sorted()

Aritmatika tanggal dan waktu

Ketiga kelas mendukung operasi aritmatika melalui metode plus dan minus. Untuk LocalDate tersedia plusDays(), plusWeeks(), plusMonths(), plusYears() dan metode minus serupa. LocalTime mendukung plusHours(), plusMinutes(), plusSeconds(), plusNanos().

LocalDateTime mewarisi semua operasi aritmatika dari kedua tipe. Fitur LocalDate: saat menambahkan bulan, hasilnya dengan benar menangani panjang bulan yang berbeda. Misalnya, 31 Januari + 1 bulan = 28 (29 di tahun kabisat) Februari.

Untuk operasi yang lebih kompleks terdapat kelas Period (untuk tanggal) dan Duration (untuk waktu). Metode plus(TemporalAmount) dan minus(TemporalAmount) menerima objek-objek ini.

kotlin
val today = LocalDate.now()
val nextWeek = today.plusDays(7)
val nextMonth = today.plusMonths(1)
val lastYear = today.minusYears(1)

val now = LocalTime.now()
val inTwoHours = now.plusHours(2)
val halfHourAgo = now.minusMinutes(30)

Contoh kode di Kotlin

Mari kita lihat contoh praktis: aplikasi untuk pencatatan shift kerja. Perlu menghitung durasi shift dan menentukan apakah shift tersebut jatuh pada jam malam. Kami menggunakan LocalTime untuk waktu mulai dan selesai, LocalDate untuk tanggal dan LocalDateTime untuk perhitungan shift yang melewati tengah malam.

kotlin
data class Shift(
    val startTime: LocalTime,
    val endTime: LocalTime,
    val date: LocalDate
) {
    fun isOvernight(): Boolean = endTime.isBefore(startTime)

    fun durationInMinutes(): Long {
        val start = LocalDateTime.of(date, startTime)
        val end = LocalDateTime.of(
            if (isOvernight()) date.plusDays(1) else date,
            endTime
        )
        return Duration.between(start, end).toMinutes()
    }
}

Contoh kedua — perhitungan usia pengguna. Kami menggunakan LocalDate untuk tanggal lahir dan membandingkannya dengan tanggal saat ini, mempertimbangkan hari dan bulan lahir.

kotlin
fun calculateAge(birthDate: LocalDate): Int {
    val today = LocalDate.now()
    val period = Period.between(birthDate, today)
    return period.years
}

Contoh ketiga — bekerja dengan notifikasi. LocalDateTime digunakan untuk menjadwalkan pengingat. Kami memeriksa apakah waktu yang dijadwalkan telah tiba.

kotlin
data class Reminder(
    val id: Long,
    val scheduledAt: LocalDateTime
) {
    fun isDue(): Boolean =
        LocalDateTime.now().isAfter(scheduledAt)
}

Dukungan di Android: level API dan desugaring

Dukungan bawaan untuk java.time muncul di Android mulai API 26 (Android 8.0 Oreo). Untuk perangkat dengan versi Android yang lebih lama perlu menggunakan desugaring — mekanisme yang menambahkan dukungan untuk API Java baru di versi awal.

Desugaring di Android Gradle Plugin dikonfigurasi melalui compileOptions di build.gradle. Cukup atur isCoreLibraryDesugaringEnabled = true dan tambahkan pustaka desugar_jdk_libs. Setelah itu java.time tersedia untuk semua level API mulai dari 14.

Untuk proyek yang tidak dapat menggunakan desugaring (misalnya, proyek legacy pada AGP di bawah 4.0), terdapat pustaka ThreeTenABP — backport java.time. Ini menyediakan kelas yang sama (LocalDate, LocalTime, LocalDateTime), tetapi dalam paket org.threeten.bp.

groovy
@Suppress("UnstableApiUsage")
android {
    compileOptions {
        isCoreLibraryDesugaringEnabled = true
    }
}

dependencies {
    "coreLibraryDesugaring"("com.android.tools:desugar_jdk_libs:2.1.4")
}

Kesalahan umum dan cara menghindarinya

Kesalahan umum pertama — menggunakan LocalDateTime di sistem terdistribusi tanpa mempertimbangkan zona waktu. Jika server berada di Europe/Moscow dan klien di Asia/Tokyo, LocalDateTime akan ditafsirkan berbeda. Solusi: gunakan Instant atau ZonedDateTime untuk data global.

Kesalahan kedua — parsing string yang salah. Secara default, LocalDate.parse() mengharapkan format ISO-8601 (yyyy-MM-dd). Jika string dalam format lain, DateTimeFormatter harus diberikan secara eksplisit. Juga harus menangani DateTimeParseException agar aplikasi tidak crash pada input yang tidak valid.

Kesalahan ketiga — mengabaikan keamanan null. LocalDate, LocalTime dan LocalDateTime adalah objek yang bisa menjadi null. Di Kotlin disarankan menggunakan tipe nullable dengan pemeriksaan eksplisit atau operator Elvis. Di Java — periksa null sebelum memanggil metode.

Kesalahan keempat — kebingungan antara LocalDateTime dan ZonedDateTime. LocalDateTime tidak berisi informasi apa pun tentang zona waktu. Jika perlu mengirimkan momen waktu absolut — gunakan tipe zonal. Jika waktu lokal cukup — tipe lokal.

Pertanyaan yang sering diajukan

Apa perbedaan antara LocalDate dan Date di Java?

Date menyimpan jumlah milidetik dari 1970-01-01 UTC, sedangkan LocalDate menyimpan tahun, bulan dan hari tanpa terikat pada zona waktu. Date bersifat mutable dan tidak thread-safe, LocalDate — immutable dan thread-safe. Date sudah usang sejak Java 8.

Bisakah LocalDateTime digunakan di database?

Ya, LocalDateTime dipetakan dengan baik ke tipe SQL TIMESTAMP WITHOUT TIME ZONE. JPA dan Room mendukungnya melalui TypeConverter. Untuk TIMESTAMP WITH TIME ZONE gunakan ZonedDateTime atau OffsetDateTime.

Bagaimana cara mendapatkan jumlah hari antara dua tanggal?

Gunakan ChronoUnit.DAYS.between(startDate, endDate). Metode ini mengembalikan long — selisih dalam hari. Untuk perhitungan yang lebih detail gunakan Period.between(), yang mengembalikan Period dengan tahun, bulan dan hari.

Apa yang harus dilakukan jika perlu menjaga presisi waktu hingga milidetik?

LocalTime mendukung presisi hingga nanodetik (9 angka desimal). Jika presisi hingga milidetik diperlukan, gunakan truncateTo(ChronoUnit.MILLIS) sebelum menyimpan. Ini mencegah masalah pembulatan saat serialisasi.

Mengapa LocalDate.now() mengembalikan tanggal yang berbeda di perangkat yang berbeda?

Metode now() menggunakan jam sistem perangkat dan zona waktu default. Jika perangkat berada di zona waktu yang berbeda, tanggal dapat berbeda. Untuk stempel waktu yang seragam gunakan Instant.now(), yang selalu mengembalikan waktu dalam UTC.

Kesimpulan

  • LocalDate — kelas immutable untuk tanggal tanpa waktu dan zona waktu. Digunakan untuk menyimpan tanggal lahir, tenggat waktu, tanggal acara.
  • LocalTime — kelas immutable untuk waktu dalam sehari dengan presisi hingga nanodetik. Cocok untuk menyimpan jam buka, durasi proses.
  • LocalDateTime — kombinasi tanggal dan waktu tanpa terikat zona. Tipe lokal paling fleksibel, tetapi tidak cocok untuk sistem terdistribusi.
  • Ketiga kelas mendukung aritmatika, perbandingan, format dan parsing melalui API seragam berbasis DateTimeFormatter.
  • Di Android java.time tersedia melalui dukungan bawaan dari API 26 atau melalui desugaring untuk versi yang lebih lama.
  • Untuk stempel waktu global dan data dengan zona waktu gunakan ZonedDateTime atau Instant daripada tipe lokal.
  • Saat parsing string, selalu berikan DateTimeFormatter untuk format non-standar dan tangani DateTimeParseException.

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