Kenapa ini penting
Setelah tahu isi Date, sekarang kamu perlu dua keterampilan praktis: membaca dan mengubah bagian-bagian tanggal (tahun, bulan, jam) serta menampilkannya dengan format yang ramah pengguna Indonesia. Pengguna tidak ingin melihat 2026-10-23T07:30:00.000Z. Mereka ingin "Jumat, 23 Oktober 2026 pukul 14.30". Struk belanja, notifikasi, laporan bulanan, dan undangan acara semuanya butuh format yang tepat.
Banyak pemula menyusun format sendiri dengan menggabungkan string dan array nama bulan. Cara itu panjang, rawan salah, dan susah diterjemahkan. JavaScript sudah menyediakan Intl.DateTimeFormat, mesin format bawaan yang paham ratusan bahasa termasuk id-ID. Di modul ini kamu belajar memakai alat yang benar.
Konsep inti
Getter: membaca bagian tanggal
| Lokal | UTC | Hasil |
|---|---|---|
getFullYear() |
getUTCFullYear() |
Tahun 4 digit |
getMonth() |
getUTCMonth() |
0-11 |
getDate() |
getUTCDate() |
Tanggal 1-31 |
getDay() |
getUTCDay() |
Hari 0 (Minggu)-6 (Sabtu) |
getHours(), getMinutes(), getSeconds(), getMilliseconds() |
versi UTC |
Jam dst |
Versi lokal memakai zona waktu komputer/browser yang menjalankan kode. Di server berzona UTC, getHours() akan berbeda dengan di laptopmu yang WIB. Ingat juga: getDate() = tanggal, getDay() = hari dalam minggu. Namanya mirip, artinya berbeda.
Setter: mengubah bagian tanggal
setFullYear, setMonth, setDate, setHours, dan seterusnya (plus versi UTC). Dua sifat penting:
- Mutable: setter mengubah object aslinya. Salin dulu dengan
new Date(d)jika aslinya masih dipakai. - Rollover otomatis:
setDate(32)di bulan Oktober otomatis menjadi 1 November. Ini berguna untuk menambah hari, tetapi bisa mengejutkan (31 Januari + 1 bulan = 3 Maret).
Format bawaan
| Method | Contoh hasil |
|---|---|
toISOString() |
2026-10-23T07:30:00.000Z (selalu UTC, untuk mesin) |
toJSON() |
Sama dengan toISOString(), dipakai JSON.stringify |
toString() |
Format panjang bahasa Inggris, tergantung lingkungan |
toLocaleDateString("id-ID", opsi) |
23/10/2026 |
toLocaleTimeString("id-ID", opsi) |
14.30.00 |
Perhatikan format Indonesia memakai titik sebagai pemisah jam (14.30), sesuai kaidah bahasa Indonesia.
Intl.DateTimeFormat
const fmt = new Intl.DateTimeFormat("id-ID", { dateStyle: "full", timeZone: "Asia/Jakarta" });
fmt.format(tanggal);
Opsi yang sering dipakai:
dateStyle/timeStyle:"full","long","medium","short".- Atau detail:
weekday,day,month("long","short","2-digit"),year,hour,minute,hour12. timeZone: selalu tentukan jika hasil harus sama di mana pun kode dijalankan.timeZoneName: "short"menambahkanWIB.
dateStyle/timeStyle tidak boleh dicampur dengan opsi detail seperti weekday (akan TypeError). Pilih salah satu pendekatan.
Membuat formatter itu relatif mahal. Jika memformat ribuan tanggal (misalnya tabel transaksi), buat formatter sekali lalu panggil format() berulang kali.
formatToParts() mengembalikan potongan-potongan (hari, bulan, tahun) sebagai array, berguna jika kamu butuh menyusun tampilan khusus.
Sebagai bonus, Intl.RelativeTimeFormat menghasilkan teks seperti "kemarin" atau "dalam 3 hari".
Contoh kode
const d = new Date("2026-10-23T14:30:00+07:00"); // Jumat, 14.30 WIB
const TZ = "Asia/Jakarta";
// 1. Getter (hasil di bawah jika komputer berzona WIB)
console.log(d.getFullYear(), d.getMonth() + 1, d.getDate()); // → 2026 10 23
console.log(d.getDay()); // → 5 (Jumat; 0 = Minggu)
console.log(d.getHours(), d.getUTCHours()); // → 14 7
// 2. Setter dengan salinan (jangan ubah aslinya)
const besok = new Date(d);
besok.setDate(besok.getDate() + 1);
console.log(d.getDate(), besok.getDate()); // → 23 24
// 3. Rollover otomatis
const akhirBulan = new Date(2026, 9, 31);
akhirBulan.setDate(akhirBulan.getDate() + 1);
console.log(akhirBulan.toDateString()); // → Sun Nov 01 2026
// Hari terakhir bulan: tanggal 0 bulan berikutnya
const hariTerakhirFeb = new Date(2026, 2, 0).getDate();
console.log(hariTerakhirFeb); // → 28
// 4. Format standar Intl dengan berbagai gaya
for (const gaya of ["full", "long", "medium", "short"]) {
const f = new Intl.DateTimeFormat("id-ID", { dateStyle: gaya, timeZone: TZ });
console.log(gaya.padEnd(6), f.format(d));
}
// → full Jumat, 23 Oktober 2026
// → long 23 Oktober 2026
// → medium 23 Okt 2026
// → short 23/10/26
// 5. Tanggal + jam + nama zona
const lengkap = new Intl.DateTimeFormat("id-ID", {
weekday: "long", day: "numeric", month: "long", year: "numeric",
hour: "2-digit", minute: "2-digit", timeZone: TZ, timeZoneName: "short",
});
console.log(lengkap.format(d)); // → Jumat, 23 Oktober 2026 pukul 14.30 WIB
// 6. Formatter dipakai ulang untuk banyak data
const fmtTanggal = new Intl.DateTimeFormat("id-ID", { day: "2-digit", month: "short", year: "numeric", timeZone: TZ });
const transaksi = [
{ ket: "Gaji", waktu: "2026-10-01T02:00:00Z" },
{ ket: "Listrik", waktu: "2026-10-05T10:15:00Z" },
];
for (const t of transaksi) {
console.log(fmtTanggal.format(new Date(t.waktu)), t.ket);
}
// → 01 Okt 2026 Gaji
// → 05 Okt 2026 Listrik
// 7. formatToParts untuk tampilan khusus
const parts = new Intl.DateTimeFormat("id-ID", { day: "numeric", month: "long", timeZone: TZ }).formatToParts(d);
const ambil = (type) => parts.find((p) => p.type === type).value;
console.log(`Tanggal ${ambil("day")} bulan ${ambil("month")}`); // → Tanggal 23 bulan Oktober
// 8. Format kunci YYYY-MM-DD sesuai WIB (untuk mengelompokkan transaksi per hari)
function kunciTanggalWIB(date) {
// locale en-CA kebetulan memformat sebagai YYYY-MM-DD
return new Intl.DateTimeFormat("en-CA", { timeZone: TZ }).format(date);
}
console.log(kunciTanggalWIB(new Date("2026-10-31T18:00:00Z"))); // → 2026-11-01 (sudah 01.00 WIB)
// 9. Waktu relatif
const rtf = new Intl.RelativeTimeFormat("id-ID", { numeric: "auto" });
console.log(rtf.format(-1, "day"), "|", rtf.format(3, "day"), "|", rtf.format(-2, "hour"));
// → kemarin | dalam 3 hari | 2 jam yang lalu
Contoh 8 sangat penting untuk aplikasi keuangan. Transaksi pada 2026-10-31T18:00:00Z jika dilihat dari UTC masih tanggal 31 Oktober, padahal di Jakarta sudah 1 November pukul 01.00. Jika laporanmu untuk pengguna Indonesia, kelompokkan berdasarkan tanggal WIB, bukan dengan memotong string ISO (toISOString().slice(0, 10)), karena string ISO selalu UTC.
Kesalahan umum
- Memotong
toISOString()untuk mendapatkan tanggal lokal. Hasilnya tanggal UTC, bisa mundur satu hari untuk waktu 00.00-06.59 WIB. GunakanIntl.DateTimeFormatdengantimeZone. - Tertukar
getDay()dangetDate().getDay()hari dalam minggu (0-6),getDate()tanggal (1-31). - Setter mengubah object asli yang masih dipakai di tempat lain. Salin dulu:
const salinan = new Date(asli). - Tidak menyebut
timeZone. Hasil format berbeda di laptop (WIB) dan server (UTC). Tentukan zona secara eksplisit. - Mencampur
dateStyledenganweekday/month. Kombinasi ini memunculkanTypeError. Pakai salah satu.
Latihan
- Mudah, Format
new Date("2026-12-25T09:00:00+07:00")menjadi"Jumat, 25 Desember 2026"memakaiIntl.DateTimeFormat. - Sedang, Buat function
awalBulan(date)danakhirBulan(date)yang mengembalikan Date baru untuk tanggal 1 dan tanggal terakhir pada bulan yang sama (waktu lokal 00.00), tanpa mengubah input. - Menantang, Kelompokkan array transaksi
{ jumlah, waktu (ISO UTC) }berdasarkan tanggal WIB (YYYY-MM-DD) dan hitung total per tanggal.
Lihat solusi
// 1
const natal = new Date("2026-12-25T09:00:00+07:00");
console.log(new Intl.DateTimeFormat("id-ID", { dateStyle: "full", timeZone: "Asia/Jakarta" }).format(natal));
// → Jumat, 25 Desember 2026
// 2
const awalBulan = (date) => new Date(date.getFullYear(), date.getMonth(), 1);
const akhirBulan = (date) => new Date(date.getFullYear(), date.getMonth() + 1, 0);
const x = new Date(2028, 1, 10);
console.log(awalBulan(x).getDate(), akhirBulan(x).getDate(), x.getDate()); // → 1 29 10
// 3
const kunci = new Intl.DateTimeFormat("en-CA", { timeZone: "Asia/Jakarta" });
const data = [
{ jumlah: 50000, waktu: "2026-10-31T16:00:00Z" }, // 23.00 WIB tgl 31
{ jumlah: 20000, waktu: "2026-10-31T17:30:00Z" }, // 00.30 WIB tgl 1
{ jumlah: 30000, waktu: "2026-11-01T03:00:00Z" },
];
const perTanggal = data.reduce((acc, { jumlah, waktu }) => {
const k = kunci.format(new Date(waktu));
acc[k] = (acc[k] ?? 0) + jumlah;
return acc;
}, {});
console.log(perTanggal); // → { '2026-10-31': 50000, '2026-11-01': 50000 }
Ringkasan
- Getter lokal (
getHours) mengikuti zona komputer, getterUTCmengikuti UTC. - Setter bersifat mutable dan melakukan rollover; salin Date sebelum diubah.
toISOString()untuk mesin (selalu UTC),Intl.DateTimeFormat("id-ID", ...)untuk manusia.- Selalu sebut
timeZone: "Asia/Jakarta"jika tampilan harus konsisten. - Buat formatter sekali dan pakai ulang; gunakan
formatToPartsuntuk tampilan khusus.