Representasi bawaan toString() seperti 2026-01-15T08:00 sangat baik untuk mesin, tetapi tidak untuk manusia: pengguna Indonesia berharap membaca “15 Januari 2026” atau “Kamis, 15 Januari 2026”, sementara pengguna Amerika Serikat akrab dengan “January 15, 2026”. Mengubah nilai date-time menjadi teks adalah pekerjaan class DateTimeFormatter — pengganti SimpleDateFormat yang immutable, thread-safe, dan sadar Locale. Pada Chapter ini kita pelajari dua gaya pemformatan: pola kustom yang kita rangkaikan sendiri huruf demi huruf, dan format bawaan yang tinggal dipilih level kerinciannya.
Pola Kustom dengan ofPattern #
Method DateTimeFormatter.ofPattern("…") membuat formatter dari pola berisi huruf-huruf bermakna khusus. Jumlah pengulangan huruf menentukan bentuk keluarannya: M menjadi 1, MM menjadi 01, MMM menjadi Jan, dan MMMM menjadi Januari. Pola juga dapat memuat teks harfiah apa pun di antara huruf-huruf itu, seperti koma atau tanda miring:
| Huruf | Makna | Contoh keluaran (15 Jan 2026) |
|---|---|---|
yyyy | tahun empat digit | 2026 |
MM | bulan dua digit | 01 |
MMM | nama bulan singkat | Jan |
MMMM | nama bulan penuh | Januari |
dd | tanggal dua digit | 15 |
d | tanggal tanpa nol di depan | 15 |
E / EEEE | nama hari singkat / penuh | Kam / Kamis |
HH | jam 24 jam dua digit | 08 |
mm | menit dua digit | 05 |
ss | detik dua digit | 03 |
z | nama zona waktu | WIB |
Huruf M untuk bulan dan m untuk menit memang mirip, begitu pula H untuk jam 24 jam dan h untuk jam 12 jam — kesalahan kapitalisasi adalah salah ketik paling umum saat menulis pola. Mari kita lihat pola-pola itu bekerja:
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Locale;
public class FormatPola {
public static void main(String[] args) {
LocalDate tanggal = LocalDate.of(2026, 1, 15);
LocalDateTime rapat = LocalDateTime.of(2026, 1, 15, 8, 5, 3);
ZonedDateTime berangkat =
ZonedDateTime.of(2026, 1, 15, 8, 0, 0, 0, ZoneId.of("Asia/Jakarta"));
Locale id = Locale.forLanguageTag("id");
DateTimeFormatter standar = DateTimeFormatter.ofPattern("dd/MM/yyyy").withLocale(id);
DateTimeFormatter panjang = DateTimeFormatter.ofPattern("dd MMMM yyyy").withLocale(id);
DateTimeFormatter hari = DateTimeFormatter.ofPattern("EEEE, dd MMMM yyyy").withLocale(id);
DateTimeFormatter singkat = DateTimeFormatter.ofPattern("E, dd MMM yy").withLocale(id);
DateTimeFormatter jamLengkap = DateTimeFormatter.ofPattern("dd/MM/yyyy HH:mm:ss");
DateTimeFormatter tanpaNol = DateTimeFormatter.ofPattern("d MMMM yyyy HH:mm").withLocale(id);
DateTimeFormatter zona = DateTimeFormatter.ofPattern("dd/MM/yyyy HH:mm z");
System.out.println("dd/MM/yyyy : " + tanggal.format(standar));
System.out.println("dd MMMM yyyy : " + tanggal.format(panjang));
System.out.println("EEEE, dd MMMM yyyy : " + tanggal.format(hari));
System.out.println("E, dd MMM yy : " + tanggal.format(singkat));
System.out.println("HH:mm:ss : " + rapat.format(jamLengkap));
System.out.println("d MMMM yyyy HH:mm : " + rapat.format(tanpaNol));
System.out.println("dengan zona : " + berangkat.format(zona));
}
}Output yang Dihasilkan:
dd/MM/yyyy : 15/01/2026
dd MMMM yyyy : 15 Januari 2026
EEEE, dd MMMM yyyy : Kamis, 15 Januari 2026
E, dd MMM yy : Kam, 15 Jan 26
HH:mm:ss : 15/01/2026 08:05:03
d MMMM yyyy HH:mm : 15 Januari 2026 08:05
dengan zona : 15/01/2026 08:00 WIBMari kita telaah baris-baris kode di atas:
- Baris 19-25: tujuh formatter dibuat sekali di awal — praktik yang tepat karena
DateTimeFormatterimmutable dan dapat dipakai ulang, termasuk sebagai konstantastatic final. - Baris 19-22:
withLocale(Locale.forLanguageTag("id"))memastikan nama hari dan bulan keluar berbahasa Indonesia; tanpa panggilan ini, formatter memakaiLocalebawaan JVM. - Baris 23 (
E, dd MMM yy): kombinasi bentuk singkat menghasilkanKam, 15 Jan 26— padat untuk tampilan tabel atau sumbu grafik. - Baris 25 (
d MMMM yyyy HH:mm): huruf tunggaldmencetak tanggal tanpa nol di depan danHH:mmmemisahkan jam-menit dengan teks harfiah titik dua. - Baris 26 (
dd/MM/yyyy HH:mm z): hurufzmenampilkan nama zonaWIB— berguna untuk nilaiZonedDateTimeagar pembaca tahu jam mana yang sedang dimaksud.
Locale Menentukan Nama Hari dan Bulan #
Pola yang sama menghasilkan teks berbeda pada Locale berbeda: MMMM menjadi Januari dalam Locale Indonesia dan January dalam Locale Inggris. Konsekuensinya, setiap formatter yang memuat huruf E, M lebih dari dua kali, atau a (penanda AM/PM) selayaknya diberi Locale eksplisit. Data nama-nama ini berasal dari CLDR (Common Locale Data Repository) yang dibundel JDK — sumber yang sama dengan Locale pada materi sebelumnya.
Format Bawaan dengan ofLocalizedDate #
Menulis pola sendiri fleksibel, tetapi untuk kebutuhan umum java.time menyediakan formatter siap pakai per Locale. Method ofLocalizedDate, ofLocalizedTime, dan ofLocalizedDateTime menerima FormatStyle dengan empat level: FULL (lengkap dengan nama hari), LONG (nama bulan penuh), MEDIUM (nama bulan singkat), dan SHORT (angka ringkas):
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.time.format.FormatStyle;
import java.util.Locale;
public class FormatLokal {
public static void main(String[] args) {
LocalDate tanggal = LocalDate.of(2026, 1, 15);
LocalDateTime rapat = LocalDateTime.of(2026, 1, 15, 8, 5);
LocalTime jam = LocalTime.of(8, 5);
Locale id = Locale.forLanguageTag("id");
Locale us = Locale.US;
FormatStyle[] daftarGaya = {
FormatStyle.FULL, FormatStyle.LONG, FormatStyle.MEDIUM, FormatStyle.SHORT
};
for (FormatStyle gaya : daftarGaya) {
String hasilId = DateTimeFormatter.ofLocalizedDate(gaya).withLocale(id).format(tanggal);
String hasilUs = DateTimeFormatter.ofLocalizedDate(gaya).withLocale(us).format(tanggal);
System.out.println(gaya + " | id : " + hasilId);
System.out.println(gaya + " | en-US : " + hasilUs);
}
DateTimeFormatter waktuId = DateTimeFormatter.ofLocalizedTime(FormatStyle.MEDIUM).withLocale(id);
DateTimeFormatter waktuUs = DateTimeFormatter.ofLocalizedTime(FormatStyle.SHORT).withLocale(us);
System.out.println("waktu MEDIUM id : " + jam.format(waktuId));
System.out.println("waktu SHORT us : " + jam.format(waktuUs));
DateTimeFormatter lengkap =
DateTimeFormatter.ofLocalizedDateTime(FormatStyle.MEDIUM).withLocale(id);
System.out.println("tanggal+waktu id : " + rapat.format(lengkap));
}
}Output yang Dihasilkan:
FULL | id : Kamis, 15 Januari 2026
FULL | en-US : Thursday, January 15, 2026
LONG | id : 15 Januari 2026
LONG | en-US : January 15, 2026
MEDIUM | id : 15 Jan 2026
MEDIUM | en-US : Jan 15, 2026
SHORT | id : 15/01/26
SHORT | en-US : 1/15/26
waktu MEDIUM id : 08.05.00
waktu SHORT us : 8:05 AM
tanggal+waktu id : 15 Jan 2026 08.05.00Perhatikan perbandingan keempat level pada keluaran: FULL menghasilkan Kamis, 15 Januari 2026 versus Thursday, January 15, 2026, MEDIUM menghasilkan 15 Jan 2026 versus Jan 15, 2026, dan SHORT menghasilkan 15/01/26 versus 1/15/26 — urutan hari-bulan-tahun ikut berubah mengikuti kebiasaan tiap Locale. Detail menarik lainnya: format waktu Indonesia memakai titik sebagai pemisah (08.05.00), sedangkan format Inggris AS memakai titik dua dan penanda AM/PM (8:05 AM) — perbedaan yang otomatis diurus CLDR.
Pemformatan mengubah nilai menjadi teks; arah sebaliknya — membaca teks dari pengguna atau sistem lain menjadi nilai — punya kesulitannya sendiri. Bab berikutnya membahas parsing: format ISO bawaan, pola kustom, dan cara menangani teks yang tidak dapat dibaca.
Referensi #
- Oracle: Class DateTimeFormatter (Java SE 25 API)
- Oracle: Enum FormatStyle (Java SE 25 API)
- dev.java: Date Time
Berkas Sumber
Berkas pendukung halaman ini dapat diunduh dan dijalankan langsung sesuai penjelasan di atas.
FormatLokal.java
Unduh berkasimport java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.time.format.FormatStyle;
import java.util.Locale;
public class FormatLokal {
public static void main(String[] args) {
LocalDate tanggal = LocalDate.of(2026, 1, 15);
LocalDateTime rapat = LocalDateTime.of(2026, 1, 15, 8, 5);
LocalTime jam = LocalTime.of(8, 5);
Locale id = Locale.forLanguageTag("id");
Locale us = Locale.US;
FormatStyle[] daftarGaya = {
FormatStyle.FULL, FormatStyle.LONG, FormatStyle.MEDIUM, FormatStyle.SHORT
};
for (FormatStyle gaya : daftarGaya) {
String hasilId = DateTimeFormatter.ofLocalizedDate(gaya).withLocale(id).format(tanggal);
String hasilUs = DateTimeFormatter.ofLocalizedDate(gaya).withLocale(us).format(tanggal);
System.out.println(gaya + " | id : " + hasilId);
System.out.println(gaya + " | en-US : " + hasilUs);
}
DateTimeFormatter waktuId = DateTimeFormatter.ofLocalizedTime(FormatStyle.MEDIUM).withLocale(id);
DateTimeFormatter waktuUs = DateTimeFormatter.ofLocalizedTime(FormatStyle.SHORT).withLocale(us);
System.out.println("waktu MEDIUM id : " + jam.format(waktuId));
System.out.println("waktu SHORT us : " + jam.format(waktuUs));
DateTimeFormatter lengkap =
DateTimeFormatter.ofLocalizedDateTime(FormatStyle.MEDIUM).withLocale(id);
System.out.println("tanggal+waktu id : " + rapat.format(lengkap));
}
}
FormatPola.java
Unduh berkasimport java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Locale;
public class FormatPola {
public static void main(String[] args) {
LocalDate tanggal = LocalDate.of(2026, 1, 15);
LocalDateTime rapat = LocalDateTime.of(2026, 1, 15, 8, 5, 3);
ZonedDateTime berangkat =
ZonedDateTime.of(2026, 1, 15, 8, 0, 0, 0, ZoneId.of("Asia/Jakarta"));
Locale id = Locale.forLanguageTag("id");
DateTimeFormatter standar = DateTimeFormatter.ofPattern("dd/MM/yyyy").withLocale(id);
DateTimeFormatter panjang = DateTimeFormatter.ofPattern("dd MMMM yyyy").withLocale(id);
DateTimeFormatter hari = DateTimeFormatter.ofPattern("EEEE, dd MMMM yyyy").withLocale(id);
DateTimeFormatter singkat = DateTimeFormatter.ofPattern("E, dd MMM yy").withLocale(id);
DateTimeFormatter jamLengkap = DateTimeFormatter.ofPattern("dd/MM/yyyy HH:mm:ss");
DateTimeFormatter tanpaNol = DateTimeFormatter.ofPattern("d MMMM yyyy HH:mm").withLocale(id);
DateTimeFormatter zona = DateTimeFormatter.ofPattern("dd/MM/yyyy HH:mm z");
System.out.println("dd/MM/yyyy : " + tanggal.format(standar));
System.out.println("dd MMMM yyyy : " + tanggal.format(panjang));
System.out.println("EEEE, dd MMMM yyyy : " + tanggal.format(hari));
System.out.println("E, dd MMM yy : " + tanggal.format(singkat));
System.out.println("HH:mm:ss : " + rapat.format(jamLengkap));
System.out.println("d MMMM yyyy HH:mm : " + rapat.format(tanpaNol));
System.out.println("dengan zona : " + berangkat.format(zona));
}
}