Teks "15 January 2026" teknis benar, tetapi terasa asing bagi pembaca Indonesia yang biasa menulis "15 Januari 2026". Fungsi format() pada objek date/time selalu menghasilkan nama hari dan nama bulan dalam bahasa Inggris karena fungsi tersebut tidak memahami locale. Chapter ini membahas dua jalur untuk memformat tanggal bagi manusia: solusi produksi berbasis ekstensi ext-intl, dan pendekatan manual murni PHP dengan array pemetaan yang bisa berjalan di server mana pun. Kita juga menutup catatan tentang strftime(), fungsi lama yang kini berstatus deprecated.
Locale dan Kenapa format() Tidak Cukup #
Locale adalah pengenal yang menggabungkan bahasa dan wilayah, misalnya id_ID untuk Bahasa Indonesia sebagaimana dipakai di Indonesia. Locale menentukan lebih dari sekadar terjemahan kata: urutan penulisan tanggal, pemisah desimal, dan nama bulan semuanya mengikuti kebiasaan setempat. Metode format() tidak menerima parameter locale, sehingga karakter F (nama bulan) atau l (nama hari) selalu menghasilkan teks Inggris. Kebutuhan locale harus dipenuhi di lapisan lain — lewat ekstensi ext-intl atau pemetaan kita sendiri.
Kenyataan Build Ini: ext-intl Tidak Aktif #
Ekstensi ext-intl adalah solusi resmi PHP untuk format locale-aware, tetapi ekstensi tersebut tidak aktif pada build yang dipakai materi ini. Kita bisa memeriksa ketersediaannya secara programatis sebelum memakai kelas-kelasnya.
<?php
var_dump(class_exists("IntlDateFormatter"));
var_dump(extension_loaded("intl"));Output yang Dihasilkan:
bool(false)
bool(false)Kedua pemeriksaan menghasilkan false pada build ini, artinya kelas IntlDateFormatter tidak dapat diinstansiasi di sini. Pola pemeriksaan seperti di atas tetap berguna di aplikasi nyata: kode dapat memilih jalur ext-intl ketika tersedia dan jatuh ke jalur manual ketika tidak. Bagian berikut menunjukkan kedua jalur tersebut.
Solusi Produksi: IntlDateFormatter #
Pada server dengan ext-intl aktif, kelas IntlDateFormatter menjadi pilihan terbaik untuk format tanggal. Konstruktornya menerima kode locale, zona waktu, dan pattern ICU yang menyerupai karakter format() dengan tambahan nama yang diterjemahkan.
<?php
$pemformat = new IntlDateFormatter(
"id_ID",
IntlDateFormatter::NONE,
IntlDateFormatter::NONE,
"Asia/Jakarta",
IntlDateFormatter::GREGORIAN,
"EEEE, d MMMM y"
);
$tanggal = new DateTimeImmutable("2026-01-15 08:00:00", new DateTimeZone("Asia/Jakarta"));
echo $pemformat->format($tanggal) . "\n";Blok di atas membutuhkan ext-intl sehingga tidak dieksekusi pada build ini. Pada server yang memiliki ekstensi tersebut, keluarannya adalah Kamis, 15 Januari 2026: pattern EEEE menghasilkan nama hari penuh, MMMM nama bulan penuh, dan d serta y tanggal dan tahun — semuanya mengikuti locale id_ID. Bila pattern dikosongkan dan tipe tanggal disetel IntlDateFormatter::LONG, hasilnya berbentuk 15 Januari 2026 tanpa nama hari.
Format Manual dengan Array Pemetaan #
Tanpa ext-intl, strategi termudah adalah memakai format() untuk bagian numerik lalu memetakan angkanya ke nama Bahasa Indonesia. Tiga karakter format() menjadi tulang punggung pendekatan ini:
| Karakter | Makna | Contoh hasil |
|---|---|---|
n | Nomor bulan 1-12 tanpa nol di depan | 1 |
N | Nomor hari ISO-8601, 1 (Senin) s.d. 7 (Minggu) | 4 |
j | Tanggal tanpa nol di depan | 15 |
<?php
$namaBulan = [
1 => "Januari", "Februari", "Maret", "April", "Mei", "Juni",
"Juli", "Agustus", "September", "Oktober", "November", "Desember",
];
$namaHari = [
1 => "Senin", "Selasa", "Rabu", "Kamis", "Jumat", "Sabtu", "Minggu",
];
$tanggal = new DateTimeImmutable("2026-01-15 08:00:00", new DateTimeZone("Asia/Jakarta"));
$indeksBulan = (int) $tanggal->format("n");
$indeksHari = (int) $tanggal->format("N");
echo "n=" . $tanggal->format("n") . " N=" . $tanggal->format("N")
. " j=" . $tanggal->format("j") . "\n";
echo $namaHari[$indeksHari] . ", " . $tanggal->format("j") . " "
. $namaBulan[$indeksBulan] . " " . $tanggal->format("Y") . "\n";Output yang Dihasilkan:
n=1 N=4 j=15
Kamis, 15 Januari 2026Mari kita telaah cara kerjanya:
- Array
$namaBulanmemakai kunci eksplisit1 =>sehingga elemen pertama berindeks1, sejajar dengan nomor bulan dari karaktern. - Array
$namaHariberindeks1sampai7mengikuti karakterNyang menjadikan Senin sebagai hari pertama. - Baris
$indeksBulan/$indeksHari: hasilformat()berupa string, lalu cast(int)mengubahnya menjadi kunci array. - Baris
echoterakhir: nama hari dan nama bulan diambil dari pemetaan, sedangkan tanggal dan tahun langsung dariformat("j")danformat("Y").
Hasil akhirnya "Kamis, 15 Januari 2026" — persis bentuk yang dibutuhkan pembaca Indonesia, tanpa satu pun ekstensi tambahan.
Fungsi Formatter Tanggal Lengkap #
Pemetaan di atas lebih awet bila dibungkus menjadi satu fungsi yang menerima objek DateTimeInterface apa pun. Fungsi berikut siap dipakai ulang di seluruh aplikasi:
<?php
function formatTanggalIndonesia(DateTimeInterface $tanggal): string
{
$namaBulan = [
1 => "Januari", "Februari", "Maret", "April", "Mei", "Juni",
"Juli", "Agustus", "September", "Oktober", "November", "Desember",
];
$namaHari = [
1 => "Senin", "Selasa", "Rabu", "Kamis", "Jumat", "Sabtu", "Minggu",
];
return $namaHari[(int) $tanggal->format("N")] . ", "
. $tanggal->format("j") . " "
. $namaBulan[(int) $tanggal->format("n")] . " "
. $tanggal->format("Y");
}
echo formatTanggalIndonesia(new DateTimeImmutable("2026-01-15 08:00:00", new DateTimeZone("Asia/Jakarta"))) . "\n";
echo formatTanggalIndonesia(new DateTimeImmutable("2026-03-01", new DateTimeZone("Asia/Jakarta"))) . "\n";
echo formatTanggalIndonesia(new DateTimeImmutable("2026-12-25", new DateTimeZone("Asia/Jakarta"))) . "\n";Output yang Dihasilkan:
Kamis, 15 Januari 2026
Minggu, 1 Maret 2026
Jumat, 25 Desember 2026Tiga pemanggilan menguji fungsi dari tiga sudut berbeda: tanggal beku lengkap dengan zona, tanggal tanpa jam, dan tanggal di akhir tahun. Tipe parameter DateTimeInterface membuat fungsi ini menerima objek DateTime maupun DateTimeImmutable sekaligus. Setiap karakter format() yang menghasilkan angka dikonversi menjadi kunci, sehingga fungsi ini tidak bergantung pada locale sistem sama sekali.
Konvensi Penulisan Jam #
Penulisan jam dalam Bahasa Indonesia formal memakai titik sebagai pemisah, misalnya 08.05, berbeda dari format teknis dua titik yang lazim di sistem komputer. PHP tidak memiliki karakter format() khusus untuk konvensi ini, tetapi kita bisa merangkainya dari komponen yang ada.
<?php
$jamKerja = new DateTimeImmutable("2026-01-15 08:05:00", new DateTimeZone("Asia/Jakarta"));
echo "Pukul " . $jamKerja->format("H") . "." . $jamKerja->format("i") . " WIB\n";
echo "Format teknis: " . $jamKerja->format("H:i:s") . "\n";Output yang Dihasilkan:
Pukul 08.05 WIB
Format teknis: 08:05:00Baris pertama menggabungkan karakter H (jam dua digit) dan i (menit dua digit) dengan pemisah titik, menghasilkan 08.05 yang sesuai kaidah penulisan Indonesia. Baris kedua menampilkan format H:i:s yang tetap layak dipakai untuk konteks teknis seperti log atau berkas data. Pilihan antara keduanya adalah keputusan tampilan: gunakan konvensi lokal untuk antarmuka pengguna, dan format teknis untuk data yang dibaca mesin.
strftime() Telah Deprecated #
Sebelum ada IntlDateFormatter, format locale-aware dikerjakan oleh pasangan setlocale() dan strftime(). Fungsi strftime() kini berstatus deprecated sejak PHP 8.1 dan memicu peringatan setiap kali dipanggil.
<?php
// Masih dapat dipanggil di PHP 8.4, tetapi deprecated dan
// memancarkan peringatan "Deprecated" pada setiap pemanggilan.
echo strftime("%d %B %Y", 1768438800);Pada build ini, pemanggilan di atas mencetak 15 January 2026 — tetap bahasa Inggris karena locale default C tidak membawa nama bulan Indonesia. Peringatan yang menyertainya menganjurkan IntlDateFormatter::format() sebagai pengganti resmi. Kode baru sebaiknya menghindari strftime() sepenuhnya.
Ringkasan #
Format locale-aware menuntut lebih dari format(): nama hari dan bulan harus mengikuti bahasa pembaca. Jalur produksinya adalah IntlDateFormatter dari ext-intl, sementara jalur portabelnya adalah array pemetaan dari karakter numerik n, N, dan j ke nama Indonesia. Fungsi strftime() yang dulu menjadi andalan kini deprecated dan sebaiknya ditinggalkan. Format tanggal hanyalah satu potong dari kebutuhan aplikasi multi-bahasa — chapter berikutnya memperluas cakupan kita ke katalog pesan, format angka, dan mata uang.