Pertanyaan “berapa lama” punya dua makna yang berbeda. Jika kita mengukur durasi pemrosesan batch dengan stopwatch, jawabannya adalah waktu fisik: satu jam berarti tepat 3600 detik. Tetapi jika kita menghitung usia seseorang atau tenor sewa perangkat, jawabannya adalah jarak kalender: “satu bulan” bisa 28, 29, 30, atau 31 hari tergantung bulan mana yang dilalui. java.time menyediakan dua alat ukur yang berbeda untuk dua makna itu — Duration untuk waktu fisik berbasis detik dan nanodetik, Period untuk rentang kalender berbasis tahun, bulan, dan hari. Pada Chapter ini kita pelajari keduanya, lalu menyiapkan pegangan memilih alat yang tepat agar hasil perhitungan tidak meleset diam-diam.
Duration untuk Waktu Fisik #
Secara internal, Duration hanya menyimpan dua angka: jumlah detik (bisa negatif) dan nanodetik pecahan di dalam detik tersebut. Factory ofHours, ofMinutes, ofSeconds, hingga ofNanos membuat durasi dari satuan waktu fisik, method between() mengukur jarak dua LocalTime, dua Instant, atau dua LocalDateTime, dan toString() memakai notasi ISO-8601 PT... — huruf P membuka period, huruf T memisahkan bagian waktu:
import java.time.Duration;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.LocalTime;
public class RentangDuration {
public static void main(String[] args) {
// Membuat durasi dari satuan waktu fisik.
Duration rapat = Duration.ofHours(1).plusMinutes(30);
System.out.println("1 jam 30 menit : " + rapat);
System.out.println("ofSeconds(90) : " + Duration.ofSeconds(90));
System.out.println("ofMinutes(45) : " + Duration.ofMinutes(45));
// Durasi di antara dua LocalTime.
Duration selisih = Duration.between(LocalTime.of(8, 0), LocalTime.of(9, 45));
System.out.println("antara 08:00-09:45 : " + selisih);
// Durasi di antara dua Instant.
Duration unduh = Duration.between(
Instant.parse("2026-01-15T01:00:00Z"),
Instant.parse("2026-01-15T01:01:45Z"));
System.out.println("durasi unduh : " + unduh);
// Konversi ke satuan lain.
System.out.println("toHours() : " + rapat.toHours());
System.out.println("toMinutes() : " + rapat.toMinutes());
System.out.println("toSeconds() : " + rapat.toSeconds());
System.out.println("toDays() 48 jam : " + Duration.ofHours(48).toDays());
// Durasi dapat dijumlahkan ke tipe bertanggal-waktu.
System.out.println("selesai proyek : " + LocalDateTime.of(2026, 1, 15, 23, 0).plus(rapat));
}
}Output yang Dihasilkan:
1 jam 30 menit : PT1H30M
ofSeconds(90) : PT1M30S
ofMinutes(45) : PT45M
antara 08:00-09:45 : PT1H45M
durasi unduh : PT1M45S
toHours() : 1
toMinutes() : 90
toSeconds() : 5400
toDays() 48 jam : 2
selesai proyek : 2026-01-16T00:30Mari kita telaah baris-baris kode di atas:
- Baris 8 (
Duration.ofHours(1).plusMinutes(30)): durasi dirakit dari satuan waktu lalu dijumlah antar durasi; hasilnyaPT1H30M— satu jam tiga puluh menit dalam notasi ISO-8601. - Baris 10-11:
ofSeconds(90)mencetakPT1M30S, menegaskan bahwaDurationselalu menata ulang satuan menjadi jam-menit-detik, bukan menyimpan “90 detik”. - Baris 14-19:
between()mengukur jarak duaLocalTimemaupun duaInstantdengan cara yang sama — selisih dihitung di garis waktu fisik. - Baris 22-25: keluarga method
toHours,toMinutes,toSeconds, dantoDaysmengonversi durasi ke satu satuan;toHours()membulatkan ke bawah sehinggaPT1H30Mmenghasilkan1, bukan1,5. - Baris 28: durasi dapat dijumlahkan langsung ke
LocalDateTime— pukul23:00maju satu setengah jam menjadi00:30di tanggal berikutnya.
Period untuk Rentang Kalender #
Period menyimpan tiga komponen terpisah: tahun, bulan, dan hari — tanpa pernah dikonversi ke satuan lain, karena makna “bulan” bergantung kalender yang dilalui. Factory of(tahun, bulan, hari) membuat periode eksplisit, between() menghitung selisih kalender dua LocalDate, dan toString() memakai notasi P1Y2M10D (satu tahun, dua bulan, sepuluh hari). Untuk total dalam satu satuan, kita meminjam ChronoUnit:
import java.time.LocalDate;
import java.time.Period;
import java.time.temporal.ChronoUnit;
public class RentangPeriod {
public static void main(String[] args) {
// Membuat periode dari komponen kalender.
Period sewa = Period.of(1, 2, 10); // 1 tahun, 2 bulan, 10 hari
System.out.println("Period.of(1, 2, 10) : " + sewa);
System.out.println("Period.ofDays(10) : " + Period.ofDays(10));
System.out.println("Period.ofWeeks(3) : " + Period.ofWeeks(3));
// Selisih kalender antara dua tanggal.
LocalDate mulai = LocalDate.of(2026, 1, 15);
LocalDate selesai = LocalDate.of(2026, 3, 20);
Period selisih = Period.between(mulai, selesai);
System.out.println("between : " + selisih);
System.out.println("getYears/getMonths/getDays: "
+ selisih.getYears() + " / " + selisih.getMonths() + " / " + selisih.getDays());
// Total dalam satu satuan memakai ChronoUnit.
System.out.println("total hari : " + ChronoUnit.DAYS.between(mulai, selesai));
System.out.println("total bulan penuh : " + ChronoUnit.MONTHS.between(mulai, selesai));
// Arah terbalik menghasilkan periode negatif.
System.out.println("between terbalik : " + Period.between(selesai, mulai));
// Periode dijumlahkan ke tanggal.
System.out.println("mulai + sewa : " + mulai.plus(sewa));
}
}Output yang Dihasilkan:
Period.of(1, 2, 10) : P1Y2M10D
Period.ofDays(10) : P10D
Period.ofWeeks(3) : P21D
between : P2M5D
getYears/getMonths/getDays: 0 / 2 / 5
total hari : 64
total bulan penuh : 2
between terbalik : P-2M-5D
mulai + sewa : 2027-03-25Baris 19-21 membedah hasil between(15 Januari, 20 Maret): komponennya 0 tahun, 2 bulan, 5 hari — dibaca sebagai “2 bulan lebih 5 hari”, bukan satu angka total. Baris 24-25 melengkapi dengan ChronoUnit.DAYS.between yang menghitung total 64 hari dan ChronoUnit.MONTHS.between yang menghitung 2 bulan penuh. Baris 28 menunjukkan arah terbalik menghasilkan periode negatif P-2M-5D, dan baris 31 menghitung 15 Januari 2026 maju satu tahun dua bulan sepuluh hari menjadi 25 Maret 2027.
Memilih Alat Ukur yang Tepat #
Perbedaan dua alat ini bukan gaya-gayaan. “Satu bulan” tidak dapat dinyatakan sebagai jumlah detik tetap — Februari 2026 berisi 28 hari sedangkan Maret berisi 31 — sehingga Duration.ofDays(30) tidak pernah setara dengan Period.ofMonths(1). Ringkasan pilihan alat ukur:
| Aspek | Duration | Period |
|---|---|---|
| Komponen internal | detik + nanodetik | tahun + bulan + hari |
Notasi toString() | PT1H30M | P1Y2M10D |
| Cocok untuk | timeout, durasi proses, stopwatch, umur token | usia, masa kerja, tenor, jadwal berulang bulanan |
| Dihitung dari | Instant, LocalTime, LocalDateTime | LocalDate (dan turunan bertanggal) |
| Total satu satuan | toHours(), toMinutes(), … | ChronoUnit.DAYS.between(…) |
Kita kini bisa merepresentasikan titik waktu dan mengukur rentangnya. Keahlian berikutnya bersifat presentasi: bagaimana mengubah semua nilai ini menjadi teks yang rapi dan berbahasa manusia? Bab berikutnya membahas DateTimeFormatter, dari pola kustom seperti dd/MM/yyyy hingga format bawaan tiap negara.
Referensi #
- Oracle: Class Duration (Java SE 25 API)
- Oracle: Class Period (Java SE 25 API)
- Oracle: Class ChronoUnit (Java SE 25 API)
- dev.java: Date Time
Berkas Sumber
Berkas pendukung halaman ini dapat diunduh dan dijalankan langsung sesuai penjelasan di atas.
RentangDuration.java
Unduh berkasimport java.time.Duration;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.LocalTime;
public class RentangDuration {
public static void main(String[] args) {
// Membuat durasi dari satuan waktu fisik.
Duration rapat = Duration.ofHours(1).plusMinutes(30);
System.out.println("1 jam 30 menit : " + rapat);
System.out.println("ofSeconds(90) : " + Duration.ofSeconds(90));
System.out.println("ofMinutes(45) : " + Duration.ofMinutes(45));
// Durasi di antara dua LocalTime.
Duration selisih = Duration.between(LocalTime.of(8, 0), LocalTime.of(9, 45));
System.out.println("antara 08:00-09:45 : " + selisih);
// Durasi di antara dua Instant.
Duration unduh = Duration.between(
Instant.parse("2026-01-15T01:00:00Z"),
Instant.parse("2026-01-15T01:01:45Z"));
System.out.println("durasi unduh : " + unduh);
// Konversi ke satuan lain.
System.out.println("toHours() : " + rapat.toHours());
System.out.println("toMinutes() : " + rapat.toMinutes());
System.out.println("toSeconds() : " + rapat.toSeconds());
System.out.println("toDays() 48 jam : " + Duration.ofHours(48).toDays());
// Durasi dapat dijumlahkan ke tipe bertanggal-waktu.
System.out.println("selesai proyek : " + LocalDateTime.of(2026, 1, 15, 23, 0).plus(rapat));
}
}
RentangPeriod.java
Unduh berkasimport java.time.LocalDate;
import java.time.Period;
import java.time.temporal.ChronoUnit;
public class RentangPeriod {
public static void main(String[] args) {
// Membuat periode dari komponen kalender.
Period sewa = Period.of(1, 2, 10); // 1 tahun, 2 bulan, 10 hari
System.out.println("Period.of(1, 2, 10) : " + sewa);
System.out.println("Period.ofDays(10) : " + Period.ofDays(10));
System.out.println("Period.ofWeeks(3) : " + Period.ofWeeks(3));
// Selisih kalender antara dua tanggal.
LocalDate mulai = LocalDate.of(2026, 1, 15);
LocalDate selesai = LocalDate.of(2026, 3, 20);
Period selisih = Period.between(mulai, selesai);
System.out.println("between : " + selisih);
System.out.println("getYears/getMonths/getDays: "
+ selisih.getYears() + " / " + selisih.getMonths() + " / " + selisih.getDays());
// Total dalam satu satuan memakai ChronoUnit.
System.out.println("total hari : " + ChronoUnit.DAYS.between(mulai, selesai));
System.out.println("total bulan penuh : " + ChronoUnit.MONTHS.between(mulai, selesai));
// Arah terbalik menghasilkan periode negatif.
System.out.println("between terbalik : " + Period.between(selesai, mulai));
// Periode dijumlahkan ke tanggal.
System.out.println("mulai + sewa : " + mulai.plus(sewa));
}
}