Disiplin timestamp

Presisi, zona waktu, dan pengurutan sebagai risiko korupsi yang senyap.

Daftar isi

Cap waktu adalah kolom identitas utama pada data time-series. Topik ini membahas tiga risiko korupsi yang senyap pada cap waktu, yaitu presisi yang tidak konsisten, zona waktu yang hilang, dan pengurutan yang dilanggar. Setelah membaca, validasi timestamp menjadi langkah wajib sebelum data masuk ke basis data, bukan pekerjaan pembersihan yang ditunda.

Presisi dan zona waktu sebagai bagian dari schema#

Presisi cap waktu adalah resolusi terkecil yang dapat dibedakan, mulai dari detik hingga nanodetik. InfluxDB menyimpan cap waktu dengan presisi nanodetik secara default, sedangkan TimescaleDB menggunakan mikrodetik pada tipe TIMESTAMPTZ. Pilihan presisi menentukan rentang representasi dan laju pertumbuhan indeks, yaitu cap waktu nanodetik mampu membedakan dua titik yang berjarak submikrodetik, tetapi memerlukan ruang penyimpanan lebih besar per baris. Sebagian besar domain tidak memerlukan presisi nanodetik, sehingga pemilihan presisi sebaiknya mengikuti kebutuhan, bukan kelaziman mesin.

Zona waktu adalah keputusan terpisah yang sering diabaikan. Cap waktu tanpa zona waktu disebut cap waktu naif, dan nilainya ambigu, yaitu 2026-11-01T00:15:00 dapat berarti pukul 00:15 di Jakarta, Tokyo, atau London. Pada basis data yang menerima data dari banyak zona, cap waktu naif menjadi sumber bug yang sulit ditelusuri, sebab selisih tujuh jam tidak terlihat pada angka, tetapi menggeser seluruh agregasi harian. Konvensi yang aman adalah menyimpan seluruh cap waktu dalam UTC dan hanya mengonversi ke zona lokal pada saat ditampilkan.

Tiga risiko korupsi yang senyap#

Risiko pertama adalah duplikasi, yaitu dua baris dengan cap waktu dan identitas yang sama. Pada basis data relasional, duplikasi dideteksi oleh primary key, tetapi pada basis data time-series yang menerima data berfrekuensi tinggi, primary key sering tidak dipasang demi kelancaran penulisan. Akibatnya, duplikasi masuk tanpa terdeteksi dan menggandakan setiap agregasi SUM atau AVG. Risikonya bukan error yang terlihat, melainkan angka yang salah pada dashboard.

Risiko kedua adalah ketidakurutan. Data time-series diharapkan terurut naik berdasarkan cap waktu, sebab indeks dan kompresi kolumnar mengasumsikan urutan tersebut. Late arrival adalah penyebab umum, yaitu titik yang ditulis setelah titik berikutnya sudah masuk. Mesin time-series umumnya menerima data tidak terurut, tetapi kompresi menjadi kurang efektif dan beberapa optimasi query mengasumsikan urutan. Risikonya bukan kegagalan query, melainkan degradasi kinerja yang akumulatif.

Risiko ketiga adalah cap waktu naif yang diasumsikan ke zona yang berbeda oleh pembaca dan penulis. Sebuah sensor yang mengirim 2026-11-01T00:15:00 tanpa zona waktu dapat dianggap UTC oleh basis data dan Asia/Jakarta oleh pengolah data, sehingga selisih tujuh jam muncul diam-diam. Cap waktu naif dapat dikonversi ke zona waktu melalui tz_localize, tetapi pilihan zona harus didasarkan pada pengetahuan tentang sumber data, bukan dugaan.

Penanganan late arrival menjadi bagian dari disiplin timestamp. Bila sebuah titik tiba terlambat, basis data tetap menulisnya pada cap waktu asli, bukan pada cap waktu penerimaan. Akibatnya, urutan baris pada penyimpanan tidak identik dengan urutan kedatangan. Banyak basis data time-series membiarkan hal ini terjadi dengan aman, tetapi chunk yang sudah dikompresi mungkin perlu ditulis ulang, sehingga biaya late arrival bukan nol. Karena itu, late arrival sebaiknya dianggarkan dalam siklus hidup data, bukan dianggap pengecualian yang jarang.

Pemeriksaan timestamp dengan pandas#

Skrip berikut membangun cap waktu dari string berzona +07:00 dan string naif, lalu mengonversi yang berzona ke UTC. Skrip mendeteksi duplikasi, ketidakurutan, dan melakukan tz_localize pada cap waktu naif. Tujuannya menunjukkan bahwa ketiga risiko dapat diperiksa secara terprogram sebelum data masuk ke basis data.

python disiplin_timestamp.py
"""Disiplin timestamp pada data time-series.

Skrip membangun cap waktu dari berbagai representasi string (dengan dan
tanpa zona waktu), mengonversi ke UTC, lalu mendeteksi tiga risiko
korupsi yang senyap, yaitu duplikasi, ketidakurutan, dan cap waktu naif
(tanpa zona waktu). Tujuannya menunjukkan bahwa timestamp bukan sekadar
kolom tanggal, melainkan keputusan presisi dan zona yang ditetapkan
sejak skema diciptakan.
"""
from __future__ import annotations

import pandas as pd


def main() -> None:
    # 1. parsing dengan zona waktu eksplisit
    str_tz = [
        "2026-11-01T00:00:00+07:00",
        "2026-11-01T00:15:00+07:00",
        "2026-11-01T00:30:00+07:00",
    ]
    tz_aware = pd.to_datetime(str_tz)
    utc = tz_aware.tz_convert("UTC")
    print("parsing string berzona +07:00, lalu konversi ke UTC:")
    for s, t_asia, t_utc in zip(str_tz, tz_aware, utc):
        print(f"  {s}  ->  asli={t_asia.isoformat()}  utc={t_utc.isoformat()}")
    print()

    # 2. cap waktu naif (tanpa zona) berisiko ambigu
    str_naif = [
        "2026-11-01T00:00:00",
        "2026-11-01T00:15:00",
        "2026-11-01T00:15:00",   # duplikat
        "2026-11-01T00:05:00",   # tidak terurut
    ]
    naive = pd.to_datetime(str_naif)
    print("cap waktu naif (tanpa zona waktu):")
    for s, n in zip(str_naif, naive):
        print(f"  {s}  ->  {n.isoformat()}")
    print()

    # 3. deteksi duplikasi
    dup = pd.Series(naive).duplicated(keep=False)
    print(f"jumlah baris duplikat: {dup.sum()}")
    print(f"  posisi: {dup[dup].index.tolist()}")
    print()

    # 4. deteksi ketidakurutan
    ser = pd.Series(naive)
    diffs = ser.diff()
    violations = diffs < pd.Timedelta(0)
    print(f"terurut naik: {ser.is_monotonic_increasing}")
    if violations.any():
        print(f"  posisi pelanggar urutan: {violations[violations].index.tolist()}")
    print()

    # 5. mengasumsikan zona pada cap waktu naif
    localized = naive.tz_localize("Asia/Jakarta")
    print("cap waktu naif diasumsikan Asia/Jakarta:")
    for n, loc in zip(naive, localized):
        print(f"  {n.isoformat()}  ->  {loc.isoformat()}")


if __name__ == "__main__":
    main()
text Keluaran
parsing string berzona +07:00, lalu konversi ke UTC:
  2026-11-01T00:00:00+07:00  ->  asli=2026-11-01T00:00:00+07:00  utc=2026-10-31T17:00:00+00:00
  2026-11-01T00:15:00+07:00  ->  asli=2026-11-01T00:15:00+07:00  utc=2026-10-31T17:15:00+00:00
  2026-11-01T00:30:00+07:00  ->  asli=2026-11-01T00:30:00+07:00  utc=2026-10-31T17:30:00+00:00

cap waktu naif (tanpa zona waktu):
  2026-11-01T00:00:00  ->  2026-11-01T00:00:00
  2026-11-01T00:15:00  ->  2026-11-01T00:15:00
  2026-11-01T00:15:00  ->  2026-11-01T00:15:00
  2026-11-01T00:05:00  ->  2026-11-01T00:05:00

jumlah baris duplikat: 2
  posisi: [1, 2]

terurut naik: False
  posisi pelanggar urutan: [3]

cap waktu naif diasumsikan Asia/Jakarta:
  2026-11-01T00:00:00  ->  2026-11-01T00:00:00+07:00
  2026-11-01T00:15:00  ->  2026-11-01T00:15:00+07:00
  2026-11-01T00:15:00  ->  2026-11-01T00:15:00+07:00
  2026-11-01T00:05:00  ->  2026-11-01T00:05:00+07:00

Keluaran di atas memperlihatkan tiga hal. Pertama, konversi +07:00 ke UTC menggeser cap waktu tujuh jam ke belakang, yaitu dari 2026-11-01T00:00:00+07:00 menjadi 2026-10-31T17:00:00+00:00. Kedua, deteksi duplikasi menemukan dua baris pada posisi 1 dan 2 dengan cap waktu identik, sebab 00:15:00 ditulis dua kali. Ketiga, deteksi ketidakurutan menemukan satu pelanggar pada posisi 3, yaitu 00:05:00 yang muncul setelah 00:15:00. Tanpa pemeriksaan ini, ketiga masalah akan masuk ke basis data dan merusak agregasi tanpa pesan error.

Kesalahan umum#

  • Menyimpan cap waktu sebagai string tanpa parsing. String tidak dapat diurutkan secara kronologis tanpa parsing, sehingga indeks pada kolom string menjadi tidak bermakna.
  • Mengonversi zona waktu dengan tz_convert pada cap waktu naif. Operasi tz_convert memerlukan cap waktu yang sudah berzona, sehingga cap waktu naif harus melalui tz_localize terlebih dahulu.
  • Mengasumsikan tz_localize tanpa argumen ambigu. Pada zona yang menerapkan daylight saving, tz_localize dapat memilih offset yang salah bila cap waktu berada di sekitar peralihan. Tentukan argumen ambiguous dan nonexistent secara eksplisit.

Ringkasan#

  • Presisi cap waktu dipilih mengikuti kebutuhan domain, dan zona waktu sebaiknya UTC di tingkat penyimpanan.
  • Tiga risiko korupsi yang senyap adalah duplikasi, ketidakurutan, dan cap waktu naif yang diasumsikan zona berbeda.
  • Pemeriksaan timestamp dengan pandas dapat dilakukan sebelum data masuk ke basis data, sehingga risiko terdeteksi tanpa menunggu pesan error dari mesin.

Referensi#