Acara-acara dunia nyata hampir selalu butuh tanggal dan jam sekaligus: rapat dimulai 15 Januari 2026 pukul 08:00, batas pengumpulan tugas 20 Maret pukul 23:59, jadwal pemutaran film malam hari. Menyimpan dua nilai terpisah — satu LocalDate dan satu LocalTime — membuka celah data tidak konsisten karena kedua nilai dapat diubah sendiri-sendiri. LocalDateTime menggabungkan keduanya menjadi satu objek yang sahih sebagai kesatuan, tetapi tetap tanpa zona waktu — murni “apa yang tertulis di kalender dinding”. Pada Chapter ini kita pelajari cara merakit, membaca kembali, memanipulasi, dan membandingkan LocalDateTime.

Membuat Objek LocalDateTime #

Ada empat jalur pembuatan yang lazim. Pertama, LocalDateTime.of(tahun, bulan, tanggal, jam, menit) mengisi seluruh komponen sekaligus. Kedua, kelebihan beban of(LocalDate, LocalTime) menggabungkan dua objek yang sudah ada. Ketiga, method atDate() milik LocalTime dan atTime() milik LocalDate merakit nilai dari salah satu sisi — bentuk yang enak dibaca saat kode berangkat dari salah satu komponen. Keempat, LocalDateTime.parse() membaca format ISO-8601 bawaan yang memisahkan tanggal dan waktu dengan huruf T:

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;

public class MembuatLocalDateTime {
    public static void main(String[] args) {
        // Jalur 1: isi semua komponen langsung.
        LocalDateTime rapat = LocalDateTime.of(2026, 1, 15, 8, 0);

        // Jalur 2: gabungkan LocalDate + LocalTime yang sudah ada.
        LocalDate tanggal = LocalDate.of(2026, 1, 15);
        LocalTime jam = LocalTime.of(10, 30);
        LocalDateTime kelas = LocalDateTime.of(tanggal, jam);

        // Jalur 3: rakit dari salah satu sisi.
        LocalDateTime lelang = jam.atDate(LocalDate.of(2026, 2, 20));
        LocalDateTime konser = tanggal.atTime(19, 45);

        // Jalur 4: parse format ISO-8601 bawaan.
        LocalDateTime dariTeks = LocalDateTime.parse("2026-01-15T08:30");

        System.out.println("rapat     : " + rapat);
        System.out.println("kelas     : " + kelas);
        System.out.println("lelang    : " + lelang);
        System.out.println("konser    : " + konser);
        System.out.println("dariTeks  : " + dariTeks);

        // Pecah kembali menjadi komponennya.
        System.out.println("toLocalDate() : " + rapat.toLocalDate());
        System.out.println("toLocalTime() : " + rapat.toLocalTime());

        // Konstanta formatter ISO bawaan mencetak detik secara eksplisit.
        System.out.println("ISO_LOCAL_DATE_TIME : " + rapat.format(DateTimeFormatter.ISO_LOCAL_DATE_TIME));
    }
}

Output yang Dihasilkan:

text
rapat     : 2026-01-15T08:00
kelas     : 2026-01-15T10:30
lelang    : 2026-02-20T10:30
konser    : 2026-01-15T19:45
dariTeks  : 2026-01-15T08:30
toLocalDate() : 2026-01-15
toLocalTime() : 08:00
ISO_LOCAL_DATE_TIME : 2026-01-15T08:00:00

Mari kita telaah baris-baris kode di atas:

  1. Baris 8 (LocalDateTime.of(2026, 1, 15, 8, 0)): seluruh komponen diisi langsung; sisanya (detik, nanodetik) bernilai nol.
  2. Baris 12-13 (of(tanggal, jam)): menggabungkan objek LocalDate dan LocalTime yang telah dibuat — berguna saat kedua komponen datang dari variabel berbeda.
  3. Baris 16-17 (atDate dan atTime): LocalTime.atDate() menempelkan tanggal pada waktu, LocalDate.atTime() menempelkan waktu pada tanggal; hasilnya sama-sama LocalDateTime.
  4. Baris 20 (parse("2026-01-15T08:30")): huruf T adalah pemisah standar ISO-8601 antara bagian tanggal dan bagian waktu.
  5. Baris 27-29: toLocalDate() dan toLocalTime() memecah objek kembali menjadi komponen tanpa salinan ganda karena keduanya immutable.

Keluaran toString() memakai format ISO-8601 dengan pemisah T, misalnya 2026-01-15T08:00. Konstanta DateTimeFormatter.ISO_LOCAL_DATE_TIME mencetak versi yang lebih lengkap dengan detik eksplisit — 2026-01-15T08:00:00 — berguna saat bertukar data antar sistem.

Mengubah, Membandingkan, dan Mengukur Durasi #

Operasi penjumlahan dan pengurangan pada LocalDateTime mengikuti kalender sungguhan. Berbeda dari LocalTime yang berputar kembali ke 00:00, penjumlahan yang melewati tengah malam menggeser tanggal ke hari berikutnya. Method Duration.between() juga bekerja pada dua objek LocalDateTime dan menghasilkan durasi waktu fisik di antara keduanya:

import java.time.Duration;
import java.time.LocalDateTime;

public class ManipulasiLocalDateTime {
    public static void main(String[] args) {
        LocalDateTime mulai = LocalDateTime.of(2026, 1, 15, 8, 0);

        // Semua operasi mengembalikan objek LocalDateTime yang baru.
        LocalDateTime selesai = mulai.plusHours(5).plusMinutes(30);
        LocalDateTime ulang = mulai.minusDays(7);
        LocalDateTime majuJam = mulai.withHour(20);

        System.out.println("mulai           : " + mulai);
        System.out.println("plus 5j 30m     : " + selesai);
        System.out.println("minus 7 hari    : " + ulang);
        System.out.println("withHour(20)    : " + majuJam);

        // Penjumlahan lintas tengah malam menggeser tanggal, bukan berputar.
        LocalDateTime lewatTengahMalam = mulai.plusHours(20);
        System.out.println("plus 20 jam     : " + lewatTengahMalam);

        LocalDateTime batas = LocalDateTime.of(2026, 1, 15, 12, 0);
        System.out.println("isBefore(batas) : " + mulai.isBefore(batas));
        System.out.println("compareTo(batas): " + mulai.compareTo(batas));

        // Durasi fisik dihitung dari dua LocalDateTime.
        Duration durasi = Duration.between(mulai, selesai);
        System.out.println("Duration.between: " + durasi);
    }
}

Output yang Dihasilkan:

text
mulai           : 2026-01-15T08:00
plus 5j 30m     : 2026-01-15T13:30
minus 7 hari    : 2026-01-08T08:00
withHour(20)    : 2026-01-15T20:00
plus 20 jam     : 2026-01-16T04:00
isBefore(batas) : true
compareTo(batas): -1
Duration.between: PT5H30M

Baris 8-10 mengembalikan objek baru untuk tiga jenis perubahan: menggeser waktu lima setengah jam, memundurkan tujuh hari, dan mengganti komponen jam menjadi 20. Baris 17-18 menyoroti perbedaan penting dengan LocalTime: menambah 20 jam ke 08:00 tanggal 15 Januari melompat ke 04:00 tanggal 16 Januari. Baris 20-22 membandingkan dua nilai — isBefore mengembalikan true dan compareTo mengembalikan nilai negatif -1 karena 08:00 lebih awal daripada 12:00. Baris 25-26 menghasilkan Duration PT5H30M (lima jam tiga puluh menit dalam notasi ISO-8601) yang akan kita bedah tuntas pada bab Duration dan Period.

Kita kini memegang tanggal, waktu, dan gabungan keduanya — semuanya nilai “waktu dinding”. Pertanyaan berikutnya mengarah ke representasi paling objektif yang bisa dibandingkan lintas zona: pada momen persis apa suatu kejadian terjadi di garis waktu semesta? Instant menjawabnya dengan jam atom UTC, bintang bab berikutnya.

Referensi #

Berkas Sumber

Berkas pendukung halaman ini dapat diunduh dan dijalankan langsung sesuai penjelasan di atas.

ManipulasiLocalDateTime.java

Unduh berkas
java
import java.time.Duration;
import java.time.LocalDateTime;

public class ManipulasiLocalDateTime {
    public static void main(String[] args) {
        LocalDateTime mulai = LocalDateTime.of(2026, 1, 15, 8, 0);

        // Semua operasi mengembalikan objek LocalDateTime yang baru.
        LocalDateTime selesai = mulai.plusHours(5).plusMinutes(30);
        LocalDateTime ulang = mulai.minusDays(7);
        LocalDateTime majuJam = mulai.withHour(20);

        System.out.println("mulai           : " + mulai);
        System.out.println("plus 5j 30m     : " + selesai);
        System.out.println("minus 7 hari    : " + ulang);
        System.out.println("withHour(20)    : " + majuJam);

        // Penjumlahan lintas tengah malam menggeser tanggal, bukan berputar.
        LocalDateTime lewatTengahMalam = mulai.plusHours(20);
        System.out.println("plus 20 jam     : " + lewatTengahMalam);

        LocalDateTime batas = LocalDateTime.of(2026, 1, 15, 12, 0);
        System.out.println("isBefore(batas) : " + mulai.isBefore(batas));
        System.out.println("compareTo(batas): " + mulai.compareTo(batas));

        // Durasi fisik dihitung dari dua LocalDateTime.
        Duration durasi = Duration.between(mulai, selesai);
        System.out.println("Duration.between: " + durasi);
    }
}

MembuatLocalDateTime.java

Unduh berkas
java
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;

public class MembuatLocalDateTime {
    public static void main(String[] args) {
        // Jalur 1: isi semua komponen langsung.
        LocalDateTime rapat = LocalDateTime.of(2026, 1, 15, 8, 0);

        // Jalur 2: gabungkan LocalDate + LocalTime yang sudah ada.
        LocalDate tanggal = LocalDate.of(2026, 1, 15);
        LocalTime jam = LocalTime.of(10, 30);
        LocalDateTime kelas = LocalDateTime.of(tanggal, jam);

        // Jalur 3: rakit dari salah satu sisi.
        LocalDateTime lelang = jam.atDate(LocalDate.of(2026, 2, 20));
        LocalDateTime konser = tanggal.atTime(19, 45);

        // Jalur 4: parse format ISO-8601 bawaan.
        LocalDateTime dariTeks = LocalDateTime.parse("2026-01-15T08:30");

        System.out.println("rapat     : " + rapat);
        System.out.println("kelas     : " + kelas);
        System.out.println("lelang    : " + lelang);
        System.out.println("konser    : " + konser);
        System.out.println("dariTeks  : " + dariTeks);

        // Pecah kembali menjadi komponennya.
        System.out.println("toLocalDate() : " + rapat.toLocalDate());
        System.out.println("toLocalTime() : " + rapat.toLocalTime());

        // Konstanta formatter ISO bawaan mencetak detik secara eksplisit.
        System.out.println("ISO_LOCAL_DATE_TIME : " + rapat.format(DateTimeFormatter.ISO_LOCAL_DATE_TIME));
    }
}