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
<?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
<?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:

text
2026-01-01 00:00:00 GMT+0000 +00:00
2026-01-01 07:00:00 WIB
2026-01-01 00:00:00 GMT+0000

Mari kita telaah baris-baris kode di atas:

  1. Baris 3: timezone default sengaja diubah ke Jakarta untuk membuktikan bahwa awalan @ tidak terpengaruh.
  2. Baris 5-6: objek dari @1767225600 terbaca sebagai 2026-01-01 00:00:00 dengan zona +00:00; singkatan T tampil sebagai GMT+0000 karena zona offset tidak memiliki nama resmi.
  3. Baris 7: setTimezone() mengubah cara membaca momen yang sama menjadi 07:00 WIB.
  4. Baris 10-11: argumen DateTimeZone yang 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
<?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:

text
Timestamp: 1768438800
2026-01-15 08:00:00 WIB

Objek 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
<?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:

text
1769817600
2026-01-05 00:00:00
2026-01-31 00:00:00

Titik 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
<?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:

text
bool(true)
Cache berakhir pada 2026-01-15 09:00:00 WIB
Durasi: 60 menit

Variabel $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
<?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:

text
PHP_INT_SIZE: 8 byte
2038-01-19 10:14:07 WIB
2038-01-19 10:14:08 WIB

Nilai 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:

KebutuhanTimestamp cocok?Alasan
Baris log serverYaRingkas, mudah diurutkan dan dihitung
TTL cache dan tokenYaCukup dibandingkan sebagai integer
Mengurutkan peristiwaYaUrutan angka = urutan waktu
Durasi antar peristiwaYaSelisih langsung dalam detik
Tampilan bagi penggunaTidakTidak ada nama bulan, hari, maupun zona
Acara berulang “setiap hari 09:00”TidakIni jam dinding, bukan momen tunggal
Tanggal lahir tanpa jamTidakTidak 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.

Referensi #