Dua sistem yang tidak saling memahami bahasa tetap bisa bersepakat tentang waktu jika keduanya memakai satu angka. Unix timestamp adalah representasi waktu sebagai jumlah detik sejak titik nol 1 Januari 1970 00:00:00 UTC — sebuah integer polos tanpa zona, tanpa nama bulan, dan tanpa format penulisan. Representasi ini mendasari baris log server, kolom database bertipe integer, masa berlaku token, hingga TTL cache. Chapter ini membahas cara PHP membaca dan menulis timestamp, kebiasaan lama strtotime(), batas tahun 2038, serta kapan timestamp tepat dipakai dan kapan justru berbahaya.
Apa Itu Unix Timestamp #
Unix timestamp menghitung waktu secara linier: setiap detik yang berlalu menambah nilai sebesar satu. Titik nolnya disebut epoch, yaitu 1970-01-01 00:00:00 UTC, sehingga timestamp 1767225600 merujuk momen 2026-01-01 00:00:00 UTC. Karena definisinya berakar pada UTC, timestamp tidak menyimpan zona apa pun; angka yang sama berarti momen yang sama di seluruh dunia. Jam dinding Jakarta dan jam dinding London yang menunjukkan angka berbeda tetap menghasilkan timestamp identik untuk momen yang sama.
time() dan Nilai yang Selalu Berubah #
Fungsi time() adalah cara tercepat mendapatkan timestamp saat ini. Nilainya bertambah satu setiap detik, sehingga hasil cetaknya tidak pernah sama antar eksekusi. Pada materi pembelajaran dan pengujian otomatis, mencetak nilai mentah time() membuat output tidak bisa dibandingkan; karena itu seluruh contoh pada chapter ini memakai nilai beku semacam 1768438800 sebagai pengganti hasil time() yang sesungguhnya.
<?php
$waktuSekarang = time(); // jumlah detik sejak 1970-01-01 00:00:00 UTC
$tokenKadaluarsa = $waktuSekarang + 3600; // token berlaku satu jam dari sekarang
$umurDetik = $tokenKadaluarsa - $waktuSekarang; // selalu bernilai 3600
Potongan di atas memperlihatkan pola umum pemakaian time(): menghitung batas waktu di masa depan dengan penjumlahan detik. Dalam aplikasi nyata, nilai variabel-variabel tersebut hidup dan terus berubah. Konstanta durasi seperti 3600 (satu jam) atau 86400 (satu hari) sengaja ditulis apa adanya agar perhitungan detiknya mudah diaudit.
Membuat Objek dari Timestamp dengan Awalan @ #
Konstruktor DateTimeImmutable mengenali string khusus berawalan @ untuk membaca timestamp. Objek hasil parsing memakai zona +00:00 tanpa memandang timezone default aplikasi maupun argumen zona yang diberikan, karena timestamp memang tidak menyimpan zona. Bila perlu menampilkannya bagi pengguna, kita konversikan eksplisit dengan setTimezone().
<?php
date_default_timezone_set("Asia/Jakarta");
$epoch = new DateTimeImmutable("@1767225600");
echo $epoch->format("Y-m-d H:i:s T P") . "\n";
echo $epoch->setTimezone(new DateTimeZone("Asia/Jakarta"))->format("Y-m-d H:i:s T") . "\n";
// Parameter kedua DIABAIKAN ketika string memakai awalan @
$dicobaLagi = new DateTimeImmutable("@1767225600", new DateTimeZone("Asia/Jakarta"));
echo $dicobaLagi->format("Y-m-d H:i:s T") . "\n";Output yang Dihasilkan:
2026-01-01 00:00:00 GMT+0000 +00:00
2026-01-01 07:00:00 WIB
2026-01-01 00:00:00 GMT+0000Mari kita telaah baris-baris kode di atas:
- Baris 3: timezone default sengaja diubah ke Jakarta untuk membuktikan bahwa awalan
@tidak terpengaruh. - Baris 5-6: objek dari
@1767225600terbaca sebagai2026-01-01 00:00:00dengan zona+00:00; singkatanTtampil sebagaiGMT+0000karena zona offset tidak memiliki nama resmi. - Baris 7:
setTimezone()mengubah cara membaca momen yang sama menjadi07:00WIB. - Baris 10-11: argumen
DateTimeZoneyang diberikan bersama awalan@diabaikan sepenuhnya — hasilnya tetap+00:00.
Mengambil Timestamp dari Objek Waktu #
Arah sebaliknya dilayani metode getTimestamp(). Metode ini mengembalikan integer dari objek mana pun, termasuk objek yang dibuat dengan zona non-UTC, karena zona hanya memengaruhi cara membaca dan bukan momen yang disimpan.
<?php
$jadwal = new DateTimeImmutable("2026-01-15 08:00:00", new DateTimeZone("Asia/Jakarta"));
$timestamp = $jadwal->getTimestamp();
echo "Timestamp: $timestamp\n";
// Uji bolak-balik: timestamp beku menjadi objek, lalu kembali ke zona asal
$kembali = (new DateTimeImmutable("@$timestamp"))->setTimezone(new DateTimeZone("Asia/Jakarta"));
echo $kembali->format("Y-m-d H:i:s T") . "\n";Output yang Dihasilkan:
Timestamp: 1768438800
2026-01-15 08:00:00 WIBObjek beku 08:00 WIB menghasilkan timestamp 1768438800 — angka yang sama dengan 01:00 UTC, sekali lagi menegaskan bahwa zona tidak mengubah nilai timestamp. Baris "@$timestamp" memanfaatkan interpolasi variabel di dalam string untuk membentuk @1768438800, lalu hasilnya dikembalikan ke zona Jakarta dan terbaca utuh sebagai 08:00 WIB. Perjalanan bolak-balik ini tidak kehilangan informasi karena informasi zona memang tidak pernah ikut tersimpan di timestamp.
Parsing Relatif dengan strtotime() #
Sebelum API objek tersedia, strtotime() adalah andalan PHP untuk menerjemahkan teks bahasa manusia menjadi timestamp. Fungsi ini menerima format tanggal Inggris seperti "next Monday" atau "+30 days", dan menerima parameter kedua berupa timestamp acuan. Tanpa acuan, parsing relatif dihitung dari waktu saat ini sehingga hasilnya berubah antar eksekusi; dengan acuan beku, hasilnya menjadi deterministik.
<?php
date_default_timezone_set("UTC");
$dasar = 1767225600; // 2026-01-01 00:00:00 UTC sebagai titik acuan beku
echo strtotime("+30 days", $dasar) . "\n";
echo date("Y-m-d H:i:s", strtotime("next Monday", $dasar)) . "\n";
echo date("Y-m-d H:i:s", strtotime("last day of January 2026", $dasar)) . "\n";Output yang Dihasilkan:
1769817600
2026-01-05 00:00:00
2026-01-31 00:00:00Titik acuan 1767225600 jatuh pada hari Kamis, 1 Januari 2026. Ekspresi "+30 days" menghasilkan 1769817600 yang merupakan 2026-01-31, "next Monday" melompat ke Senin berikutnya yaitu 2026-01-05, dan "last day of January 2026" tepat mengembalikan akhir bulan. Untuk kode baru, pertimbangkan DateTimeImmutable::createFromFormat() yang lebih ketat dan lebih mudah divalidasi daripada teks bebas.
Timestamp untuk Log dan Cache #
Titik kuat timestamp adalah aritmetikanya: selisih dua timestamp adalah durasi dalam detik, dan penjumlahan menghasilkan momen baru. Pola ini terlihat pada log berstempel waktu dan cache berbasis TTL (time to live).
<?php
date_default_timezone_set("Asia/Jakarta");
// Nilai beku menggantikan time() agar contoh dapat direproduksi
$sekarang = 1768438800; // 2026-01-15 08:00:00 WIB
$kadaluarsaCache = $sekarang + 3600;
var_dump($sekarang < $kadaluarsaCache);
echo "Cache berakhir pada " . date("Y-m-d H:i:s T", $kadaluarsaCache) . "\n";
$mulai = 1768438800;
$selesai = 1768442400;
echo "Durasi: " . ($selesai - $mulai) / 60 . " menit\n";Output yang Dihasilkan:
bool(true)
Cache berakhir pada 2026-01-15 09:00:00 WIB
Durasi: 60 menitVariabel $sekarang menahan nilai beku yang setara pukul 08:00 WIB, lalu batas cache dihitung dengan menambah 3600 detik. Pemeriksaan $sekarang < $kadaluarsaCache menirukan cara aplikasi memutuskan cache masih segar atau tidak. Dua baris terakhir membuktikan durasi antar peristiwa cukup dihitung dengan pengurangan: selisih 3600 detik dibagi 60 menghasilkan tepat 60 menit.
Batas Tahun 2038 dan PHP 64-bit #
Integer bertanda 32-bit berhenti di nilai 2147483647, yang jatuh pada 2038-01-19 03:14:07 UTC. Sistem yang menyimpan timestamp dalam integer 32-bit akan mengalami masalah Year 2038 ketika nilainya meluap. PHP modern dikompilasi 64-bit sehingga jauh aman; konstanta PHP_INT_SIZE mengonfirmasi lebar integer pada proses yang sedang berjalan.
<?php
date_default_timezone_set("Asia/Jakarta");
echo "PHP_INT_SIZE: " . PHP_INT_SIZE . " byte\n";
echo date("Y-m-d H:i:s T", 2147483647) . "\n";
echo date("Y-m-d H:i:s T", 2147483648) . "\n";Output yang Dihasilkan:
PHP_INT_SIZE: 8 byte
2038-01-19 10:14:07 WIB
2038-01-19 10:14:08 WIBNilai PHP_INT_SIZE sebesar 8 byte menandakan integer 64-bit, yang sanggup merepresentasikan timestamp hingga ratusan miliar tahun ke depan. Dua baris berikutnya menampilkan detik terakhir era 32-bit dan detik sesudahnya; keduanya terbaca tanpa masalah pada proses 64-bit. Kewaspadaan tetap diperlukan ketika berinteraksi dengan sistem lawas, perangkat tertanam, atau protokol yang masih membatasi timestamp pada 32-bit.
Kapan Timestamp Tepat Dipakai #
Timestamp adalah alat mesin-ke-mesin, bukan alat tampilan. Tabel berikut merangkum keputusan pemakaiannya:
| Kebutuhan | Timestamp cocok? | Alasan |
|---|---|---|
| Baris log server | Ya | Ringkas, mudah diurutkan dan dihitung |
| TTL cache dan token | Ya | Cukup dibandingkan sebagai integer |
| Mengurutkan peristiwa | Ya | Urutan angka = urutan waktu |
| Durasi antar peristiwa | Ya | Selisih langsung dalam detik |
| Tampilan bagi pengguna | Tidak | Tidak ada nama bulan, hari, maupun zona |
| Acara berulang “setiap hari 09:00” | Tidak | Ini jam dinding, bukan momen tunggal |
| Tanggal lahir tanpa jam | Tidak | Tidak ada momen jam yang relevan |
Untuk tampilan, konversikan timestamp menjadi objek DateTimeImmutable lalu format sesuai locale seperti pada chapter Locale-Aware Formatting
. Acara berulang sebaiknya disimpan sebagai aturan jam dinding plus zona bernama, sedangkan tanggal lahir paling aman disimpan sebagai string "2012-05-17" atau tipe DATE di database.
Ringkasan #
Unix timestamp merepresentasikan momen sebagai jumlah detik sejak epoch UTC, bebas zona dan bebas format. Kita bisa membuat objek dari timestamp dengan awalan @, membacanya kembali lewat getTimestamp(), dan memanfaatkan strtotime() dengan acuan beku untuk parsing relatif. Timestamp sangat tepat untuk log, TTL, dan pengurutan, tetapi bukan untuk tampilan; manusia membutuhkan nama bulan dalam bahasanya sendiri — kebutuhan yang kita penuhi pada chapter berikutnya tentang format locale-aware.