Topik ini membahas keluarga jenis data tanggal dan waktu, yaitu date, time, timestamp, timestamptz, dan interval, beserta disiplin zona waktu yang menyertainya. Penanganan waktu adalah sumber bug yang paling sering muncul pada aplikasi lintas wilayah, dan topik ini meletakkan aturannya sejak awal.
timestamp dan timestamptz#
timestamp menyimpan tanggal dan jam tanpa informasi zona, sedangkan timestamptz, kependekan timestamp with time zone, menyimpan satu titik waktu universal. Server menyimpan timestamptz dalam UTC di dalam, lalu menampilkannya menurut zona waktu sesi yang sedang berjalan. Perbedaan ini terlihat ketika nilai yang sama dilihat dari zona berbeda.
# timestamp tanpa zona versus timestamptz dengan zona
psql -U postgres -d perpustakaan <<'SQL'
SET TIME ZONE 'Asia/Jakarta';
SELECT '2025-04-15 08:00'::timestamp AS tanpa_zona, '2025-04-15 08:00+07'::timestamptz AS dengan_zona;
RESET TIME ZONE;
SQLSET
tanpa_zona | dengan_zona
---------------------+------------------------
2025-04-15 08:00:00 | 2025-04-15 08:00:00+07
(1 row)
RESETKolom dengan_zona membawa penanda +07 karena sesi memakai Asia/Jakarta, sedangkan kolom tanpa_zona diterima apa adanya tanpa konversi. Apabila sesi berpindah zona, kolom dengan_zona tetap menunjuk momen yang sama dan hanya tampak berubah, sedangkan kolom tanpa_zona tidak pernah tahu dirinya milik zona mana. Sifat inilah yang membuat timestamptz menjadi pilihan baku untuk peristiwa, yaitu momen yang sungguh terjadi di dunia.
date, time, dan interval#
date menyimpan tanggal kalender tanpa jam, time menyimpan jam sehari, dan interval menyimpan durasi. Ketiganya beraritmetika secara alami, sehingga jatuh tempo dihitung dengan menambahkan interval ke tanggal, dan selisih dua timestamp menghasilkan interval.
# aritmetika tanggal dan selisih waktu
psql -U postgres -d perpustakaan <<'SQL'
SELECT DATE '2025-04-15' + INTERVAL '90 days' AS jatuh_tempo;
SELECT TIMESTAMP '2025-05-01 10:00' - TIMESTAMP '2025-04-15 08:00' AS selisih;
SQL jatuh_tempo
---------------------
2025-07-14 00:00:00
(1 row)
selisih
------------------
16 days 02:00:00
(1 row)Interval disimpan sebagai bulan, hari, dan jam terpisah, karena satu bulan tidak berarti tiga puluh hari. Pemisahan ini membuat DATE '2025-01-31' + INTERVAL '1 month' menghasilkan 28 Februari pada tahun non kabisat secara wajar, sebagaimana tafsir kalender, bukan 2 Maret.
Fungsi waktu dan nilai bawaan#
Waktu saat ini tersedia melalui CURRENT_DATE untuk tanggal dan now() untuk timestamptz, dan keduanya dipakai sebagai nilai bawaan kolom pencatatan. Tabel berikut memperlihatkan pola kolom dibuat yang mengisi dirinya sendiri.
# kolom pencatatan waktu dengan nilai bawaan
psql -U postgres -d perpustakaan <<'SQL'
CREATE TABLE catatan_uji (isi TEXT, dibuat TIMESTAMPTZ NOT NULL DEFAULT now());
INSERT INTO catatan_uji (isi) VALUES ('contoh catatan');
SELECT isi, dibuat >= '2026-01-01' AS tercatat_mutakhir FROM catatan_uji;
DROP TABLE catatan_uji;
SQLCREATE TABLE
INSERT 0 1
isi | tercatat_mutakhir
----------------+-------------------
contoh catatan | t
(1 row)
DROP TABLEKeluarannya membandingkan nilai bawaan dengan tanggal acuan alih-alih menampilkan jam server, karena jam eksekusi berbeda setiap saat. Pola pembanding inilah yang layak dicontoh pada uji otomatis, sedangkan pada layar administrator nilai now() ditampilkan langsung tanpa masalah.
Disiplin zona waktu#
Aturan praktisnya tiga lapis. Pertama, kolom peristiwa memakai timestamptz, dan aplikasi mengirim maupun membacanya dalam zona yang diinginkan sesi. Kedua, nama zona memakai nama IANA seperti Asia/Jakarta, bukan singkatan seperti WIB, karena singkatan berbagi makna antar wilayah dan berubah sejarahnya. Ketiga, waktu yang disimpan tanpa zona hanya untuk fakta kalender murni, misalnya jadwal piket yang tetap berlaku 08.00 lokal tanpa peduli kapan itu.
# tampilan satu momen dari dua zona berbeda
psql -U postgres -d perpustakaan <<'SQL'
SET TIME ZONE 'Asia/Jakarta';
SELECT '2025-04-15 08:00+07'::timestamptz AS versi_jakarta;
SET TIME ZONE 'Europe/London';
SELECT '2025-04-15 08:00+07'::timestamptz AS versi_london;
RESET TIME ZONE;
SQLSET
versi_jakarta
------------------------
2025-04-15 08:00:00+07
(1 row)
SET
versi_london
------------------------
2025-04-15 02:00:00+01
(1 row)
RESETSatu momen, dua tampilan, dan tidak ada konversi yang berlaku ganda karena penyimpanannya memang UTC. Musim panas di wilayah pengguna ditangani zona IANA secara otomatis, sehingga aplikasi tidak pernah menghitung offset dengan tangan.
Kesalahan umum#
Kesalahan pertama adalah memakai timestamp tanpa zona untuk peristiwa aplikasi global, yang membuat satu kolom mengandung campuran makna waktu dari banyak wilayah dan tidak dapat diperbaiki mundur. Kesalahan kedua adalah mengira timestamptz menyimpan zona asli peristiwa, padahal yang tersimpan hanya titik UTC dan tampilannya mengikuti zona sesi, sehingga zona asal harus disimpan di kolom terpisah bila memang dibutuhkan. Kesalahan ketiga adalah menghitung durasi lintas musim panas dengan mengurangi dua timestamp tanpa zona, yang melampaui atau kekurangan satu jam pada tanggal pergantian.
Kesalahan keempat adalah memperlakukan interval sebagaimana bilangan, misalnya mengira INTERVAL '30 days' sama dengan INTERVAL '1 month' di seluruh bulan. Keduanya hanya sama pada bulan berpanjang tiga puluh hari, dan pembagian interval pada aritmetika kalender perlu dicek dengan fungsi date_trunc atau make_interval.
Ringkasan#
- timestamp menyimpan waktu tanpa zona, sedangkan timestamptz menyimpan titik UTC dan menampilkannya menurut zona sesi.
- date, time, dan interval beraritmetika secara alami, dan interval menyimpan bulan, hari, serta jam terpisah.
- CURRENT_DATE dan now() menjadi nilai bawaan kolom pencatatan, dan pembandingan eksplisit lebih aman daripada menampilkan jam server pada uji otomatis.
- Nama zona memakai IANA seperti Asia/Jakarta, dan waktu tanpa zona hanya untuk fakta kalender murni.
Referensi#
- Date/Time Types — PostgreSQL Documentation — Dokumentasi resmi date, time, timestamp, dan interval.
- Date/Time Functions and Operators — PostgreSQL Documentation — Fungsi aritmetika waktu dan zona.
- Locale and Formatting — PostgreSQL Documentation — Pengaturan zona waktu dan format tampilan.