1. Mengapa Wajib Menggunakan DateTimeImmutable dan Bukan DateTime?
Di PHP, terdapat dua kelas tanggal utama yang mengimplementasikan DateTimeInterface:
DateTime(Mutable / Berbahaya): Ketika Anda memanggil$tanggal->modify('+7 days'), objek$tanggalaslinya ikut berubah di tempat! Jika objek$tanggalMulaitersebut sudah dikirimkan ke fungsi lain, seluruh bagian program yang memegang referensi ke$tanggalMulaitiba-tiba melihat tanggal yang sudah bergeser 7 hari tanpa sadar!DateTimeImmutable(Immutable / Standar Terbaik): Setiap pemanggilan metode pengubah seperti$tanggal->modify('+7 days')atau$tanggal->setTimezone(...)selalu mengembalikan instans objek baru dan membiarkan objek aslinya utuh 100%!
<?php
declare(strict_types=1);
$mulaiLangganan = new DateTimeImmutable('2026-10-16 08:00:00', new DateTimeZone('UTC'));
// modify() pada DateTimeImmutable menghasilkan objek baru tanpa mengubah $mulaiLangganan!
$akhirLangganan = $mulaiLangganan->modify('+30 days');
echo $mulaiLangganan->format('Y-m-d'); // Tetap "2026-10-16"
echo $akhirLangganan->format('Y-m-d'); // "2026-11-15"
DateTimeImmutableSejak PHP 8.4, tersedia metode statis langsung DateTimeImmutable::createFromTimestamp(int|float $timestamp) (yang mendukung angka bulat detik maupun float dengan pecahan mikrodetik!), serta metode getMicrosecond() dan setMicrosecond(int $microsecond)!
2. Arsitektur Zona Waktu: Simpan dalam UTC, Tampilkan Sesuai Zona Pengguna!
Pengguna situs Anda di Indonesia tersebar di tiga zona waktu (WIB / Asia/Jakarta UTC+7, WITA / Asia/Makassar UTC+8, dan WIT / Asia/Jayapura UTC+9), belum lagi pengguna di luar negeri.
Jika Anda menyimpan jam lokal mentah tanpa zona waktu di basis data, urutan kejadian antara pengguna di Jakarta dan Makassar akan menjadi kacau! Aturan emas di sistem produksi:
- Di Server dan Basis Data: Selalu simpan waktu dalam zona waktu universal
UTC(atau gunakan tipe kolomTIMESTAMPTZdi PostgreSQL). - Di Lapisan Tampilan (View / API): Konversikan objek
DateTimeImmutabledariUTCke zona waktu pengguna menggunakan->setTimezone(new DateTimeZone($zonaPengguna))tepat saat hendak ditampilkan!
<?php
declare(strict_types=1);
// 1. Waktu kejadian disimpan sebagai UTC di database
$waktuKejadianUtc = new DateTimeImmutable('2026-10-16 07:30:00', new DateTimeZone('UTC'));
// 2. Konversi ke WIB (Asia/Jakarta), WITA (Asia/Makassar), dan WIT (Asia/Jayapura) saat ditampilkan:
$wib = $waktuKejadianUtc->setTimezone(new DateTimeZone('Asia/Jakarta'));
$wita = $waktuKejadianUtc->setTimezone(new DateTimeZone('Asia/Makassar'));
$wit = $waktuKejadianUtc->setTimezone(new DateTimeZone('Asia/Jayapura'));
echo $wib->format('Y-m-d H:i T') . "\n"; // "2026-10-16 14:30 WIB"
echo $wita->format('Y-m-d H:i T') . "\n"; // "2026-10-16 15:30 WITA"
echo $wit->format('Y-m-d H:i T') . "\n"; // "2026-10-16 16:30 WIT"
Menghitung Selisih Waktu dengan diff() dan DateInterval
<?php
declare(strict_types=1);
$tenggat = new DateTimeImmutable('2026-12-31 23:59:59', new DateTimeZone('Asia/Jakarta'));
$sekarang = new DateTimeImmutable('2026-10-16 14:30:00', new DateTimeZone('Asia/Jakarta'));
$selisih = $sekarang->diff($tenggat);
// %a mencetak total jumlah hari penuh di antara kedua tanggal
echo $selisih->format('Tersisa %a hari (%m bulan, %d hari, %h jam)');
3. Memformat Mata Uang dan Tanggal Bahasa Indonesia dengan Ekstensi intl
Fungsi DateTimeImmutable::format('l, d F Y') selalu mencetak nama hari dan bulan dalam bahasa Inggris ("Friday, 16 October 2026"). Untuk mencetak tanggal Bahasa Indonesia yang baku ("Jumat, 16 Oktober 2026") dan mata uang Rupiah yang presisi, gunakan kelas IntlDateFormatter dan NumberFormatter dari ekstensi standar intl:
<?php
declare(strict_types=1);
// 1. Memformat Mata Uang Rupiah dengan NumberFormatter (ext-intl)
$pemformatUang = new NumberFormatter('id_ID', NumberFormatter::CURRENCY);
$pemformatUang->setAttribute(NumberFormatter::FRACTION_DIGITS, 0);
echo $pemformatUang->formatCurrency(1_450_000, 'IDR') . "\n"; // "Rp1.450.000"
// 2. Memformat Tanggal Lengkap Bahasa Indonesia dengan IntlDateFormatter
$pemformatTanggal = new IntlDateFormatter(
locale: 'id_ID',
dateType: IntlDateFormatter::FULL,
timeType: IntlDateFormatter::SHORT,
timezone: 'Asia/Jakarta',
);
$waktu = new DateTimeImmutable('2026-10-16 07:30:00', new DateTimeZone('UTC'));
echo $pemformatTanggal->format($waktu) . "\n";
// Keluaran: "Jumat, 16 Oktober 2026 14.30"
Bentuk keluaran IntlDateFormatter (misalnya ada tidaknya kata "pukul" antara tanggal dan jam, dan spasi pada Rp1.450.000) bergantung pada versi ICU/CLDR yang terpasang di server; jalankan kodenya di lingkungan Anda untuk melihat hasil persisnya.
Latihan Praktik: Konverter Jadwal Webinar Lintas Zona Waktu Nusantara
Buatlah berkas jadwal-webinar.php:
- Buat fungsi
buatJadwalWebinar(string $waktuMulaiWib, int $durasiMenit): arrayyang menerima string waktu WIB (mis.'2026-11-10 19:00:00'), membuatDateTimeImmutabledengan zona'Asia/Jakarta', dan menghitung waktu selesainya dengan->modify("+{$durasiMenit} minutes"). - Kembalikan jadwal lengkap dalam format UTC (untuk disimpan ke database) serta tampilan waktu dalam WIB, WITA, dan WIT!