TIMESTAMPTZ vs TIMESTAMP: dasbor dan API PostgreSQL
TIMESTAMPTZ vs TIMESTAMP di PostgreSQL: bagaimana pilihan tipe memengaruhi dasbor, respons API, konversi zona waktu, dan bug pada perubahan waktu musim panas (DST).

Masalah sebenarnya: satu momen, banyak interpretasi
Sebuah event terjadi sekali, tetapi dilaporkan dengan selusin cara berbeda. Basis data menyimpan sebuah nilai, API men-serialisasi-nya, dasbor mengelompokkannya, dan setiap orang melihatnya di zona waktu mereka sendiri. Jika salah satu lapisan membuat asumsi berbeda, baris yang sama bisa tampak seperti dua momen berbeda.
Itulah mengapa pilihan antara TIMESTAMPTZ dan TIMESTAMP bukan sekadar preferensi tipe data. Pilihan itu memutuskan apakah nilai yang disimpan merepresentasikan instant tertentu dalam waktu, atau waktu dinding yang hanya masuk akal di tempat tertentu.
Yang biasanya rusak pertama adalah: dasbor penjualan menampilkan total harian berbeda di New York dan Berlin. Grafik per jam kehilangan satu jam atau menggandakan jam saat perubahan daylight saving time (DST). Log audit tampak tidak berurutan karena dua sistem “sepakat” pada tanggal tapi tidak pada instant yang sebenarnya.
Model sederhana membantu Anda menghindari masalah:
- Storage: apa yang Anda simpan di PostgreSQL dan apa maknanya.
- Display: bagaimana Anda memformatnya di UI, ekspor, atau laporan.
- User locale: zona waktu dan aturan kalender penonton, termasuk DST.
Campur aduk ketiganya dan Anda mendapatkan bug pelaporan yang sulit dideteksi. Tim support mengekspor “ticket dibuat kemarin” dari dasbor, lalu membandingkannya dengan laporan API. Keduanya tampak masuk akal, tetapi satu menggunakan batas tengah malam lokal penonton sementara yang lain menggunakan UTC.
Tujuannya sederhana: untuk setiap nilai waktu, buat dua pilihan yang jelas. Putuskan apa yang Anda simpan, dan putuskan apa yang Anda tampilkan. Kejelasan itu harus melekat pada model data, respons API, dan dasbor sehingga semua orang melihat garis waktu yang sama.
Apa arti TIMESTAMP dan TIMESTAMPTZ sebenarnya
Di PostgreSQL, namanya menyesatkan. Mereka tampak seperti menggambarkan apa yang disimpan, tapi sebenarnya lebih menggambarkan bagaimana PostgreSQL menafsirkan input dan memformat output.
TIMESTAMP (alias timestamp without time zone) hanyalah tanggal kalender dan waktu jam, seperti 2026-01-29 09:00:00. Tidak ada zona waktu yang terikat. PostgreSQL tidak akan mengonversinya untuk Anda. Dua orang di zona waktu berbeda bisa membaca TIMESTAMP yang sama dan mengasumsikan momen dunia nyata yang berbeda.
TIMESTAMPTZ (alias timestamp with time zone) merepresentasikan titik nyata dalam waktu. Pikirkan sebagai sebuah instant. PostgreSQL menormalkannya secara internal (efektif ke UTC), lalu menampilkannya dalam zona waktu sesi yang sedang digunakan.
Perilaku yang mendasari sebagian besar kejutan adalah:
- Pada input: PostgreSQL mengonversi nilai
TIMESTAMPTZke satu instant yang bisa dibandingkan. - Pada output: PostgreSQL memformat instant itu menggunakan zona waktu sesi saat ini.
- Untuk
TIMESTAMP: tidak ada konversi otomatis pada input atau output.
Contoh kecil menunjukkan perbedaannya. Misalkan aplikasi Anda menerima 2026-03-08 02:30 dari seorang pengguna. Jika Anda memasukkannya ke kolom TIMESTAMP, PostgreSQL menyimpan tepat nilai waktu dinding itu. Jika waktu lokal itu tidak ada karena lonjakan DST, Anda mungkin tidak menyadarinya sampai pelaporan rusak.
Jika Anda memasukkan ke TIMESTAMPTZ, PostgreSQL memerlukan zona waktu untuk menafsirkan nilai tersebut. Jika Anda memberikan 2026-03-08 02:30 America/New_York, PostgreSQL mengonversinya menjadi instant (atau melempar error tergantung aturan dan nilai tepatnya). Nanti, dasbor di London akan menampilkan jam lokal yang berbeda, tetapi itu adalah instant yang sama.
Salah kaprah umum: orang melihat “with time zone” dan mengharapkan PostgreSQL menyimpan label zona waktu asli. Ia tidak melakukan itu. PostgreSQL menyimpan momen, bukan label. Jika Anda perlu menyimpan zona waktu asli pengguna untuk ditampilkan (misalnya, “tampilkan dalam waktu lokal pelanggan”), simpan zona itu secara terpisah sebagai kolom teks.
Zona waktu sesi: pengaturan tersembunyi di balik banyak kejutan
PostgreSQL punya pengaturan yang diam-diam mengubah apa yang Anda lihat: zona waktu sesi. Dua orang bisa menjalankan query yang sama pada data yang sama dan mendapatkan waktu jam yang berbeda karena sesi mereka menggunakan zona waktu berbeda.
Ini terutama memengaruhi TIMESTAMPTZ. PostgreSQL menyimpan instant mutlak, lalu menampilkannya di zona waktu sesi. Pada TIMESTAMP (tanpa zona), PostgreSQL memperlakukan nilai sebagai waktu kalender biasa. Ia tidak menggesernya untuk ditampilkan, tapi zona waktu sesi masih bisa menyulitkan ketika Anda mengonversinya ke TIMESTAMPTZ atau membandingkannya dengan nilai yang sadar zona waktu.
Zona waktu sesi sering disetel tanpa Anda sadari: konfigurasi saat aplikasi dimulai, parameter driver, connection pool yang memakai sesi lama, alat BI dengan default sendiri, job ETL yang mewarisi pengaturan lokal server, atau konsol SQL manual yang menggunakan preferensi laptop Anda.
Beginilah tim berujung berdebat. Misalkan sebuah event disimpan sebagai 2026-03-08 01:30:00+00 di kolom TIMESTAMPTZ. Sesi dasbor di America/Los_Angeles akan menampilkannya sebagai waktu lokal malam sebelumnya, sementara sesi API di UTC menampilkan waktu jam yang berbeda. Jika grafik mengelompokkan per hari menggunakan hari lokal sesi, Anda bisa mendapatkan total harian yang berbeda.
-- Make your output consistent for a reporting job
SET TIME ZONE 'UTC';
SELECT created_at, date_trunc('day', created_at) AS day_bucket
FROM events;
Untuk apa pun yang menghasilkan laporan atau respons API, buat zona waktu menjadi eksplisit. Tetapkan saat koneksi dibuat (atau jalankan SET TIME ZONE terlebih dahulu), pilih satu standar untuk output mesin (sering kali UTC), dan untuk laporan “waktu bisnis lokal” tetapkan zona bisnis di dalam job, bukan di laptop seseorang. Jika Anda menggunakan koneksi ber-pool, reset pengaturan sesi saat koneksi dikeluarkan dari pool.
Bagaimana dasbor bisa rusak: pengelompokan, bucket, dan celah DST
Dasbor terlihat sederhana: hitung pesanan per hari, tunjukkan pendaftaran per jam, bandingkan minggu ke minggu. Masalah muncul ketika basis data menyimpan satu “moment” tetapi grafik mengubahnya menjadi banyak “hari,” tergantung siapa yang melihat.
Jika Anda mengelompokkan per hari menggunakan zona waktu lokal pengguna, dua orang bisa melihat tanggal berbeda untuk event yang sama. Pesanan yang dibuat pukul 23:30 di Los Angeles sudah menjadi “besok” di Berlin. Dan jika SQL Anda mengelompokkan dengan DATE(created_at) pada TIMESTAMP polos, Anda tidak mengelompokkan berdasarkan instant nyata. Anda mengelompokkan berdasarkan pembacaan waktu dinding tanpa zona.
Grafik per jam menjadi lebih rumit saat DST. Di musim semi, satu jam lokal tidak pernah terjadi, jadi grafik bisa menunjukkan celah. Di musim gugur, satu jam lokal terjadi dua kali, sehingga Anda bisa mendapatkan lonjakan atau bucket ganda jika query dan dasbor tidak sepakat tentang 01:30 yang mana.
Pertanyaan praktis membantu: apakah Anda mem-plot momen nyata (aman untuk dikonversi), atau waktu jadwal lokal (tidak boleh dikonversi)? Dasbor hampir selalu menginginkan momen nyata.
Kapan mengelompokkan berdasarkan UTC vs zona waktu bisnis
Pilih satu aturan pengelompokan dan pakai di mana-mana (SQL, API, alat BI), kalau tidak total akan bergeser.
Kelompokkan berdasarkan UTC ketika Anda menginginkan rangkaian global dan konsisten (kesehatan sistem, traffic API, pendaftaran global). Kelompokkan berdasarkan zona waktu bisnis ketika “hari” memiliki makna hukum atau operasional (hari toko, SLA support, penutupan keuangan). Kelompokkan berdasarkan zona waktu penonton hanya ketika personalisasi lebih penting daripada perbandingan (feed aktivitas pribadi).
Berikut pola untuk pengelompokan “hari bisnis” yang konsisten:
SELECT date_trunc('day', created_at AT TIME ZONE 'America/New_York') AS business_day,
count(*)
FROM orders
GROUP BY 1
ORDER BY 1;
Label yang mencegah ketidakpercayaan
Orang berhenti mempercayai grafik ketika angka melompat dan tak ada yang bisa menjelaskan kenapa. Beri label aturan itu langsung di UI: “Daily orders (America/New_York)” atau “Hourly events (UTC)”. Gunakan aturan yang sama di ekspor dan API.
Aturan sederhana untuk pelaporan dan API
Putuskan apakah Anda menyimpan sebuah instant atau bacaan jam lokal. Mencampur keduanya adalah tempat di mana dasbor dan API mulai berbeda.
Set aturan yang membuat pelaporan dapat diprediksi:
- Simpan event dunia nyata sebagai instant menggunakan
TIMESTAMPTZ, dan anggap UTC sebagai sumber kebenaran. - Simpan konsep bisnis seperti “billing day” terpisah sebagai
DATE(atau field waktu lokal jika benar-benar perlu waktu dinding), karena maksudnya terikat pada lokasi. - Di API, kembalikan timestamp dalam ISO 8601 dan konsisten: selalu sertakan offset (seperti
+02:00) atau selalu gunakanZuntuk UTC. - Lakukan konversi di tepi (UI dan lapisan pelaporan). Hindari mengonversi bolak-balik di dalam logika database dan job latar.
Mengapa ini bertahan: dasbor mengelompokkan dan membandingkan rentang. Jika Anda menyimpan instant (TIMESTAMPTZ), PostgreSQL dapat mengurutkan dan memfilter event dengan andal meskipun terjadi pergeseran DST. Lalu Anda memilih bagaimana menampilkannya atau mengelompokkannya. Jika Anda menyimpan waktu dinding lokal (TIMESTAMP) tanpa zona waktu, PostgreSQL tidak tahu apa artinya, sehingga pengelompokan bisa berubah ketika zona waktu sesi berubah.
Jaga “tanggal bisnis lokal” terpisah karena itu bukan instant. “Kirim pada 2026-03-08” adalah keputusan tanggal, bukan sebuah momen. Jika Anda memaksanya ke timestamp, hari-hari yang terkena DST bisa membuat jam lokal hilang atau terduplikasi, yang nanti muncul sebagai celah atau lonjakan.
Langkah demi langkah: memilih tipe yang tepat untuk tiap nilai waktu
Memilih antara TIMESTAMPTZ vs TIMESTAMP dimulai dengan satu pertanyaan: apakah nilai ini mendeskripsikan momen nyata yang terjadi, atau waktu lokal yang ingin Anda pertahankan persis seperti tertulis?
1) Pisahkan event nyata dari waktu jadwal lokal
Buat inventaris cepat kolom Anda.
Event nyata (klik, pembayaran, login, pengiriman, pembacaan sensor, pesan support) biasanya harus disimpan sebagai TIMESTAMPTZ. Anda menginginkan satu instant yang tidak ambigu, meskipun orang melihatnya dari zona waktu berbeda.
Waktu jadwal lokal berbeda: “Toko buka pukul 09:00”, “Jendela pickup 16:00–18:00”, “Tagihan berjalan setiap tanggal 1 pukul 10:00 waktu lokal”. Ini sering lebih baik disimpan sebagai TIMESTAMP ditambah kolom zona waktu terpisah, karena maksudnya terkait dengan jam dinding suatu lokasi.
2) Pilih standar dan dokumentasikan
Untuk sebagian besar produk, default yang baik adalah: simpan waktu event dalam UTC, tampilkan dalam zona waktu pengguna. Dokumentasikan ini di tempat yang dibaca orang: catatan skema, dokumentasi API, dan deskripsi dasbor. Juga definisikan apa yang dimaksud dengan “hari bisnis” (hari UTC, hari zona bisnis, atau hari lokal penonton), karena pilihan itu menentukan pelaporan harian.
Checklist singkat yang bekerja dalam praktik:
- Tandai setiap kolom waktu sebagai “event instant” atau “local schedule”.
- Default untuk event instant adalah
TIMESTAMPTZdisimpan dalam UTC. - Saat mengubah skema, backfill dengan hati-hati dan validasi beberapa baris secara manual.
- Standarkan format API (selalu sertakan
Zatau offset untuk instant). - Tetapkan zona waktu sesi secara eksplisit di job ETL, konektor BI, dan worker latar.
Berhati-hatilah dengan pekerjaan “convert and backfill”. Mengubah tipe kolom bisa diam-diam mengubah makna jika nilai lama ditafsirkan di bawah zona waktu sesi yang berbeda.
Kesalahan umum yang menyebabkan off-by-one-day dan bug DST
Sebagian besar bug waktu bukanlah “PostgreSQL aneh.” Mereka muncul dari menyimpan nilai yang tampak benar dengan makna yang salah, lalu membiarkan lapisan berbeda menebak konteks yang hilang.
Kesalahan 1: Menyimpan waktu dinding seolah-olah absolut
Perangkap umum adalah menyimpan waktu dinding lokal (misalnya “2026-03-29 09:00” di Berlin) di TIMESTAMPTZ. PostgreSQL memperlakukannya sebagai instant dan mengonversinya berdasarkan zona waktu sesi saat itu. Jika maksudnya selalu pukul 9 AM waktu lokal, Anda baru saja kehilangan makna itu. Menampilkan baris yang sama di sesi dengan zona waktu berbeda akan menggeser jam yang ditampilkan.
Untuk janji temu, simpan waktu lokal sebagai TIMESTAMP plus zona waktu terpisah (atau lokasi). Untuk event yang terjadi pada satu momen (pembayaran, login), simpan instant sebagai TIMESTAMPTZ.
Kesalahan 2: Lingkungan berbeda, asumsi berbeda
Laptop Anda, staging, dan production mungkin tidak berbagi zona waktu yang sama. Satu lingkungan berjalan di UTC, lainnya di waktu lokal, dan laporan “group by day” mulai berbeda. Datanya tidak berubah, pengaturan sesi yang berubah.
Kesalahan 3: Menggunakan fungsi waktu tanpa tahu janjinya
now() dan current_timestamp stabil dalam satu transaksi. clock_timestamp() berubah setiap pemanggilan. Jika Anda menghasilkan timestamp di beberapa titik dalam satu transaksi dan mencampur fungsi-fungsi ini, pengurutan dan durasi bisa tampak aneh.
Kesalahan 4: Mengonversi dua kali (atau nol kali)
Bug API yang sering: aplikasi mengonversi waktu lokal ke UTC, mengirimnya sebagai string naif, lalu basis data mengonversi lagi karena mengira inputnya lokal. Sebaliknya juga terjadi: aplikasi mengirim waktu lokal tetapi melabelinya dengan Z (UTC), sehingga bergeser saat dirender.
Kesalahan 5: Mengelompokkan berdasarkan date tanpa menyatakan zona waktu yang dimaksud
“Total harian” tergantung pada batas hari yang Anda maksud. Jika Anda mengelompokkan dengan date(created_at) pada TIMESTAMPTZ, hasil mengikuti zona waktu sesi. Event larut malam bisa pindah ke hari sebelumnya atau berikutnya.
Sebelum merilis dasbor atau API, periksa dasar-dasarnya: pilih satu zona waktu pelaporan per chart dan terapkan konsisten, sertakan offset (atau Z) di payload API, samakan staging dan production pada kebijakan zona waktu, dan jelaskan zona waktu yang dimaksud saat mengelompokkan.
Pemeriksaan cepat sebelum Anda kirimkan dasbor atau API
Bug waktu jarang muncul dari satu query buruk. Mereka terjadi karena storage, pelaporan, dan API masing-masing membuat sedikit asumsi berbeda.
Gunakan checklist singkat sebelum rilis:
- Untuk event dunia nyata (pendaftaran, pembayaran, ping sensor), simpan instant sebagai
TIMESTAMPTZ. - Untuk konsep lokal bisnis (billing day, reporting date), simpan
DATEatauTIME, bukan timestamp yang akan Anda “konversi nanti.” - Di job terjadwal dan runner laporan, tetapkan zona waktu sesi dengan sengaja.
- Di respons API, sertakan offset atau
Z, dan pastikan klien menguraikannya sebagai waktu yang sadar zona waktu. - Uji minggu transisi DST untuk setidaknya satu zona target.
Validasi end-to-end cepat: pilih satu event edge-case yang diketahui (misalnya, 2026-03-08 01:30 di zona yang mengamati DST) dan ikuti dari penyimpanan, output query, JSON API, hingga label akhir di chart. Jika chart menunjukkan hari yang benar tapi tooltip menunjukkan jam yang salah (atau sebaliknya), Anda punya mismatch konversi.
Contoh: mengapa dua tim berbeda pendapat tentang angka hari yang sama
Tim support di New York dan tim finansial di Berlin melihat dasbor yang sama. Server database berjalan di UTC. Semua orang bersikeras angka mereka benar, tetapi “kemarin” berbeda tergantung siapa yang Anda tanya.
Event-nya: tiket pelanggan dibuat pukul 23:30 di New York pada 10 Maret. Itu adalah 04:30 UTC pada 11 Maret, dan 05:30 di Berlin. Satu momen nyata, tiga tanggal kalender berbeda.
Jika waktu pembuatan tiket disimpan sebagai TIMESTAMP (tanpa zona) dan aplikasi Anda menganggapnya “lokal”, Anda bisa diam-diam menulis ulang sejarah. New York mungkin memperlakukan 2026-03-10 23:30 sebagai waktu New York, sementara Berlin menafsirkan nilai tersimpan yang sama sebagai waktu Berlin. Baris yang sama jatuh pada hari berbeda untuk penonton yang berbeda.
Jika disimpan sebagai TIMESTAMPTZ, PostgreSQL menyimpan instant secara konsisten dan hanya mengonversinya ketika seseorang melihat atau memformatnya. Inilah alasan mengapa pilihan TIMESTAMPTZ vs TIMESTAMP mengubah apa arti “sehari” dalam laporan.
Perbaikannya adalah memisahkan dua gagasan: instant saat event terjadi, dan tanggal pelaporan yang ingin Anda gunakan.
Polanya praktis:
- Simpan waktu event sebagai
TIMESTAMPTZ. - Putuskan aturan pelaporan: viewer-local (dasbor personal) atau satu zona bisnis (keuangan perusahaan).
- Hitung tanggal pelaporan saat query dengan aturan itu: konversi instant ke zona yang dipilih, lalu ambil date.
Langkah selanjutnya: standarkan penanganan waktu di seluruh stack Anda
Jika penanganan waktu tidak ditulis, setiap laporan baru menjadi permainan tebak-tebakan. Usahakan perilaku waktu yang membosankan dan dapat diprediksi di database, API, dan dasbor.
Tulis “kontrak waktu” singkat yang menjawab tiga pertanyaan:
- Standar waktu event: simpan instant event sebagai
TIMESTAMPTZ(biasanya dalam UTC) kecuali ada alasan kuat untuk tidak melakukannya. - Zona waktu bisnis: pilih satu zona untuk pelaporan, dan gunakan konsisten ketika Anda mendefinisikan “hari,” “minggu,” dan “bulan.”
- Format API: selalu kirim timestamp dengan offset (ISO 8601 dengan
Zatau+/-HH:MM) dan dokumentasikan apakah field berarti “instant” atau “waktu dinding lokal.”
Tambahkan tes kecil di sekitar awal dan akhir DST. Mereka menangkap bug mahal lebih awal. Misalnya, validasi bahwa query “total harian” stabil untuk zona bisnis tetap melintasi perubahan DST, dan bahwa input API seperti 2026-11-01T01:30:00-04:00 dan 2026-11-01T01:30:00-05:00 diperlakukan sebagai dua instant berbeda.
Rencanakan migrasi dengan hati-hati. Mengubah tipe dan asumsi di tempat bisa diam-diam menulis ulang sejarah di grafik. Pendekatan yang lebih aman adalah menambahkan kolom baru (misalnya, created_at_utc TIMESTAMPTZ), isi kembali dengan konversi yang sudah direview, ubah pembacaan untuk menggunakan kolom baru, lalu perbarui penulisan. Pertahankan laporan lama dan baru berdampingan sebentar agar pergeseran angka harian terlihat jelas.
Jika Anda menginginkan satu tempat untuk menegakkan “kontrak waktu” ini di model data, API, dan layar, setup build terpadu membantu. AppMaster (appmaster.io) menghasilkan backend, web app, dan API dari satu project, yang mempermudah menjaga aturan penyimpanan dan tampilan timestamp konsisten seiring aplikasi Anda berkembang.
FAQ
Gunakan TIMESTAMPTZ untuk segala hal yang terjadi pada satu momen nyata (pendaftaran, pembayaran, login, pesan, ping sensor). Ia menyimpan satu instant yang tidak ambigu dan aman diurutkan, difilter, dan dibandingkan antar sistem. Gunakan TIMESTAMP hanya ketika nilai dimaksudkan sebagai waktu dinding yang harus tetap persis seperti tertulis, biasanya dipasangkan dengan kolom zona waktu atau lokasi terpisah.
TIMESTAMPTZ merepresentasikan satu instant nyata dalam waktu; PostgreSQL menormalkannya secara internal lalu menampilkannya sesuai zona waktu sesi Anda. TIMESTAMP hanyalah tanggal dan waktu jam tanpa zona, jadi PostgreSQL tidak akan menggesernya otomatis. Perbedaan utamanya adalah makna: instant versus waktu dinding lokal.
Karena zona waktu sesi mengontrol bagaimana TIMESTAMPTZ diformat pada output dan bagaimana beberapa input ditafsirkan. Dua alat bisa menanyakan baris yang sama dan menunjukkan waktu jam yang berbeda jika satu sesi diatur ke UTC dan yang lain ke America/Los_Angeles. Untuk laporan dan API, tetapkan zona waktu sesi secara eksplisit agar hasil tidak bergantung pada default tersembunyi.
Karena “sehari” bergantung pada batas zona waktu. Jika satu dasbor mengelompokkan berdasarkan waktu lokal penonton sementara lainnya mengelompokkan berdasarkan UTC (atau zona bisnis tertentu), event larut malam bisa jatuh pada tanggal yang berbeda dan mengubah total harian. Perbaiki dengan memilih satu aturan pengelompokan per diagram (UTC atau zona bisnis tertentu) dan gunakan secara konsisten di SQL, BI, dan ekspor.
DST menciptakan jam lokal yang hilang atau terduplikasi, yang dapat menghasilkan celah atau bucket ganda saat mengelompokkan berdasarkan waktu lokal. Jika data Anda merepresentasikan momen nyata, simpan sebagai TIMESTAMPTZ dan pilih zona waktu diagram yang jelas untuk pengelompokan. Juga uji minggu transisi DST untuk target zona Anda agar menemukan kejutan lebih awal.
Tidak, PostgreSQL tidak menyimpan label zona waktu asli dengan TIMESTAMPTZ; ia menyimpan instant. Saat Anda query, PostgreSQL menampilkannya di zona waktu sesi, yang bisa berbeda dari zona pengguna asal. Jika Anda perlu “menampilkannya dalam zona waktu pelanggan”, simpan zona tersebut secara terpisah di kolom lain.
Kembalikan timestamp ISO 8601 yang menyertakan offset, dan konsisten. Default sederhana adalah selalu mengembalikan UTC dengan Z untuk instant event, lalu biarkan klien melakukan konversi untuk tampilan. Hindari mengirim string “naif” seperti 2026-03-10 23:30:00 karena klien akan menebak zona dengan berbeda-beda.
Konversi lakukan di tepi: simpan instant event sebagai TIMESTAMPTZ, lalu konversikan ke zona yang diinginkan ketika Anda menampilkan atau mengelompokkan untuk pelaporan. Hindari konversi bolak-balik di dalam trigger, job latar, dan ETL kecuali Anda memiliki kontrak yang jelas. Sebagian besar masalah pelaporan muncul dari konversi ganda atau dari mencampur nilai naif dan yang sadar zona waktu.
Gunakan DATE untuk konsep bisnis yang benar-benar tanggal, seperti “billing day”, “reporting date”, atau “delivery date”. Gunakan TIME (atau TIMESTAMP ditambah zona waktu terpisah) untuk jadwal seperti “buka pukul 09:00 waktu lokal”. Jangan memaksa ini ke TIMESTAMPTZ kecuali Anda benar-benar bermaksud satu instant, karena DST dan perubahan zona bisa menggeser makna yang dimaksud.
Pertama, tentukan apakah nilainya adalah instant (TIMESTAMPTZ) atau waktu dinding lokal (TIMESTAMP plus zona), lalu tambahkan kolom baru daripada menulis ulang di tempat. Isi kembali (backfill) dengan konversi yang sudah direview di bawah zona waktu sesi yang diketahui, dan validasi baris contoh di sekitar tengah malam dan batas DST. Jalankan laporan lama dan baru berdampingan sementara sehingga perubahan total terlihat jelas sebelum menghapus kolom lama.


