Skip to content
Kembali ke Blog
Tutorial

Apa yang Tersimpan di Kolom timestamp PostgreSQL?

Cara PostgreSQL menyimpan timestamp vs timestamptz di balik layar. Pelajari perbedaannya, jebakan timezone, dan tipe mana yang tepat untuk proyek Anda.

6 menit baca

PostgreSQL timestamp vs timestamptz: Apa Sebenarnya yang Tersimpan di Balik Layar?

PostgreSQL menyimpan baik timestamp maupun timestamptz sebagai satu integer 64-bit: jumlah mikrodetik sejak 1970-01-01 00:00:00 UTC. Perbedaannya muncul hanya saat data diformat untuk konsumsi manusia.

Mengapa Ini Membingungkan Banyak Orang?

  • Dua kolom, satu tanggal… dua hasil query yang berbeda
  • Aplikasi Anda menyisipkan 2025-07-29 10:00, tapi tim lain melihat 02:00
  • Frontend merender string ISO yang tidak cocok dengan log backend

Dua Kaleng Buah Persik: Satu Polos, Satu Berlabel

Tipe DataNama ResmiNilai TersimpanApa yang Terjadi saat SELECT
timestamptimestamp without time zonehitungan mikrodetik mentahDikirim kembali tanpa perubahan — Postgres tidak pernah menebak timezone
timestamptztimestamp with time zonehitungan mikrodetik yang samaPostgres menerapkan pengaturan TimeZone sesi tepat sebelum mengirim teks

Analogi

  • timestamp = stoples buah persik tanpa label asal. Anda tahu itu buah, tapi tidak tahu di mana diproduksi.
  • timestamptz = stoples yang dicap “Dibuat di UTC+8.” Siapa pun yang membukanya bisa memutuskan apakah perlu mengkonversi label nutrisi.

Di Balik Layar: Ini Hanya Angka Besar

2000-01-01 00:00:00 UTC  → 0
2000-01-01 00:00:01 UTC  → 1 000 000
  • Unit: mikrodetik (seperjuta detik)
  • Rentang: 4713 SM – 294276 M — disetujui Indiana Jones
  • Penyimpanan untuk timestamp dan timestamptz identik; yang berbeda adalah interpretasinya

Demo 15 Detik

-- Client berpikir dalam waktu Shanghai
SET TimeZone = 'Asia/Shanghai';

CREATE TABLE demo (
  created_ts timestamp,
  created_tz timestamptz
);

INSERT INTO demo VALUES ('2025-07-29 10:00', '2025-07-29 10:00');
QueryHasilAlasan
SELECT created_ts FROM demo;2025-07-29 10:00:00Nilai mentah, tanpa kalkulasi TZ
SELECT created_tz FROM demo;2025-07-29 10:00:00+08Tag diterapkan saat output
SET TimeZone = 'UTC'; lalu select2025-07-29 02:00:00+00Momen yang sama, lensa baru

Aritmetika Timestamp dan Interval

Salah satu aspek paling praktis dari timestamp PostgreSQL adalah aritmetika interval. Karena kedua tipe menyimpan hitungan mikrodetik, Anda bisa menambah dan mengurangi interval secara langsung:

-- Tambah 3 jam dan 30 menit
SELECT '2025-07-29 10:00'::timestamptz + INTERVAL '3 hours 30 minutes';
-- → 2025-07-29 13:30:00+08

-- Temukan selisih antara dua timestamp
SELECT '2025-07-30 09:00'::timestamptz - '2025-07-29 10:00'::timestamptz;
-- → 23:00:00  (sebuah interval)

-- Ekstrak field tertentu
SELECT EXTRACT(EPOCH FROM '2025-07-29 10:00:00+08'::timestamptz);
-- → 1753768800  (Unix timestamp dalam detik)

-- Potong ke batas hari (berguna untuk agregasi harian)
SELECT date_trunc('day', '2025-07-29 15:42:19+08'::timestamptz);
-- → 2025-07-29 00:00:00+08

Fungsi EXTRACT(EPOCH FROM ...) sangat berguna ketika Anda perlu meneruskan timestamp ke sistem eksternal yang mengharapkan detik epoch Unix. Sebaliknya, Anda bisa mengkonversi epoch kembali ke timestamp:

SELECT to_timestamp(1753768800);
-- → 2025-07-29 10:00:00+08  (dalam sesi Asia/Shanghai)

Poin penting yang halus: aritmetika interval dengan timestamp (tanpa timezone) mengabaikan transisi DST sepenuhnya, sementara timestamptz menghormatinya. Ini berarti menambahkan INTERVAL '1 day' ke nilai timestamptz yang melintasi batas DST akan mengembalikan waktu jam dinding yang sama dengan benar — bukan tepat 24 jam kemudian.

Pertimbangan Indexing dan Performa

Baik timestamp maupun timestamptz disimpan sebagai integer 8-byte, jadi tidak ada perbedaan performa antara keduanya untuk penyimpanan atau indexing. Index B-tree bekerja identik pada kedua tipe karena perbandingan yang mendasarinya hanyalah perbandingan integer.

Namun, ada beberapa pertimbangan praktis:

  • Range query: WHERE created_at > '2025-07-01' bekerja efisien dengan index pada kedua tipe. Dengan timestamptz, PostgreSQL mengkonversi literal ke UTC sebelum perbandingan, sehingga index tetap digunakan.
  • Partition key: Saat menggunakan range partitioning pada kolom timestamp, timestamptz umumnya lebih aman karena batas partisi tidak ambigu (selalu UTC). Dengan timestamp, batas seperti '2025-07-01 00:00' bisa berarti hal berbeda untuk sesi yang berbeda.
  • Functional index: Jika Anda sering melakukan query berdasarkan tanggal saja (mengabaikan waktu), pertimbangkan index pada date_trunc('day', created_at) untuk mempercepat query agregasi harian.

Jebakan Umum & Solusi Cepat

1. Pengguna berbeda, jam berbeda

  • Penyebab: client menggunakan pengaturan TimeZone yang berbeda dengan timestamptz
  • Solusi: tetap gunakan semua timestamp + sepakati satu zona, atau paksa SET TimeZone = 'UTC' saat inisialisasi koneksi

Pola umum dalam kode aplikasi adalah mengatur timezone sekali saat inisialisasi connection pool:

-- Dalam setup koneksi Anda (misalnya, konfigurasi pg pool)
SET timezone = 'UTC';

Ini memastikan semua sesi melihat representasi UTC yang sama, dan application layer Anda menangani konversi ke waktu lokal untuk tampilan.

2. Menyimpan “waktu jam dinding” tapi memilih tipe yang salah

  • Kalender bisnis (jam toko, deadline) harus menggunakan timestamp
  • Alur kerja lintas negara (pesanan, log) harus menyimpan UTC di timestamptz

Tesnya sederhana: jika pertanyaannya adalah “pada momen apa ini terjadi?” gunakan timestamptz. Jika pertanyaannya adalah “jam berapa di dinding?” gunakan timestamp.

3. API yang bergeser

  • Selalu kirimkan timestamptz sebagai string ISO-8601 dengan offset (Z atau +08:00)
  • Biarkan UI memformat secara lokal

4. Membandingkan timestamp lintas tipe

Mencampurkan timestamp dan timestamptz dalam perbandingan atau join adalah sumber bug yang halus:

-- Berbahaya: cast implisit menerapkan timezone sesi
SELECT * FROM orders o
JOIN schedules s ON o.created_tz = s.start_ts;
-- PostgreSQL melakukan cast s.start_ts ke timestamptz menggunakan timezone sesi
-- Sesi yang berbeda bisa mendapatkan hasil join yang berbeda!

Solusi: selalu lakukan cast secara eksplisit saat membandingkan lintas tipe, atau standarisasi pada satu tipe per domain.

5. Jebakan default ORM

Banyak ORM (Django, SQLAlchemy, ActiveRecord) default ke timestamp tanpa timezone. Periksa file migrasi Anda — jika aplikasi Anda melayani pengguna lintas timezone, override default ke timestamptz. Di Django, atur USE_TZ = True di settings. Di SQLAlchemy, gunakan DateTime(timezone=True).

Cheat Sheet: Mana yang Harus Saya Gunakan?

Kalender lokal saja → timestamp
Apa pun yang global → timestamptz (simpan UTC)
  • Laporan keuangan, jadwal kelas → timestamp
  • Log audit, pesanan e-commerce → timestamptz

Verifikasi dalam Hitungan Detik dengan Go Tools

KebutuhanToolCara
Inspeksi nilai epoch dari SQLEpoch ConverterTempel 1690622400, tekan Convert
Bandingkan dua timezone sekilasTimezone ConverterMasukkan 10:00 Asia/Shanghai
Rapikan JSON massal dengan field waktuJSON FormatterDrop payload, prettify & scan

Semua utilitas berjalan sepenuhnya di browser Anda — data tidak pernah meninggalkan mesin Anda.

Pertanyaan yang Sering Diajukan

Apa perbedaan antara timestamp dan timestamptz di PostgreSQL?

timestamp (tanpa time zone) menyimpan nilai date-time apa adanya, tanpa konteks timezone. timestamptz (dengan time zone) mengkonversi input ke UTC untuk penyimpanan dan mengkonversi kembali ke timezone sesi saat pengambilan. Gunakan timestamptz untuk hampir semua kasus — ini mencegah bug terkait timezone di sistem terdistribusi.

Apakah PostgreSQL benar-benar menyimpan timezone di timestamptz?

Tidak — meskipun namanya, PostgreSQL tidak menyimpan timezone itu sendiri. Ia mengkonversi input ke UTC dan menyimpan hanya nilai UTC (hitungan mikrodetik dari 2000-01-01). Saat pengambilan, ia mengkonversi dari UTC ke timezone apa pun yang ditentukan oleh pengaturan timezone sesi Anda. Informasi timezone asli dibuang.

Bagaimana cara mengubah timezone untuk sesi PostgreSQL?

Jalankan SET timezone = 'America/New_York'; untuk mengubah timezone sesi. Ini memengaruhi bagaimana nilai timestamptz ditampilkan dan diinterpretasikan. Untuk default seluruh server, atur timezone di postgresql.conf. Selalu gunakan nama timezone IANA (seperti Asia/Shanghai) daripada singkatan (seperti CST) untuk menghindari ambiguitas.

Haruskah saya menggunakan timestamp atau timestamptz untuk menyimpan waktu event?

Gunakan timestamptz untuk hampir semua hal — aksi pengguna, panggilan API, log audit, dan event terjadwal. Hanya gunakan timestamp (tanpa timezone) untuk waktu abstrak yang tidak terikat pada momen tertentu, seperti “toko buka pukul 09:00” yang berarti jam 9 pagi dalam timezone lokal apa pun, bukan instant UTC tertentu.

Bagaimana PostgreSQL menangani daylight saving time dengan timestamptz?

PostgreSQL menangani DST dengan benar saat menggunakan timestamptz karena ia menyimpan semuanya dalam UTC secara internal. Saat Anda mengambil nilai, PostgreSQL mengkonversi dari UTC menggunakan aturan DST saat ini untuk timezone sesi Anda. Ini berarti instant UTC tersimpan yang sama menampilkan waktu lokal yang berbeda dengan benar sebelum dan sesudah transisi DST.

Untuk panduan komprehensif tentang Unix timestamp — termasuk penanganan presisi, praktik terbaik timezone, dan contoh kode dalam JavaScript, Python, dan Go — baca Panduan Unix Timestamp kami.

Penutup

  • Kedua tipe waktu Postgres adalah penghitung mikrodetik; labelnya adalah satu-satunya perbedaan
  • Memilih yang salah berarti timestamp yang membingungkan dan perhitungan yang rusak
  • Uji, konversi, dan periksa kewarasan dengan tool yang tepat untuk menghemat berjam-jam debugging

Artikel Terkait

Lihat semua artikel