Cara Menggunakan Unix Timestamps untuk Date Range Queries

Membuat query untuk record dalam rentang tanggal — "tampilkan semuanya dari 30 hari terakhir," "cari order antara 1 Januari dan 31 Maret" — adalah salah satu operasi paling umum di aplikasi apa pun yang menggunakan database. Cara Anda menyimpan dan membuat query timestamp memiliki dampak signifikan pada seberapa sederhana dan andal query tersebut.

Unix timestamps (integer yang merepresentasikan detik sejak Unix epoch) sering kali merupakan pilihan terbaik untuk ini, tetapi hanya jika Anda tahu cara menggunakannya dengan benar. Berikut panduan praktisnya.

Mengapa Unix Timestamps Membuat Range Queries Lebih Sederhana

Ketika timestamp disimpan sebagai integer, date range query menjadi perbandingan numerik sederhana:

SELECT * FROM events
WHERE created_at >= 1704067200
  AND created_at < 1706745600;

Itu saja. Tidak ada parsing string, tidak ada konversi timezone, tidak ada semantik BETWEEN yang perlu dikhawatirkan. Database hanya membandingkan dua angka.

Bandingkan dengan pendekatan formatted datetime string:

SELECT * FROM events
WHERE created_at >= '2024-01-01 00:00:00'
  AND created_at < '2024-02-01 00:00:00';

Ini terlihat mirip, tetapi menimbulkan beberapa pertanyaan: Timezone apa yang digunakan untuk '2024-01-01 00:00:00'? Apakah application server Anda menginterpretasinya sama dengan database server? Apa yang terjadi ketika user di timezone berbeda menjalankan query yang sama?

Unix timestamps menghindari semua ini. Mereka selalu UTC, selalu tidak ambigu, selalu berupa angka. Konversi ke waktu lokal terjadi di display layer, bukan dalam query.

Menghitung Timestamps untuk Common Date Ranges

Untuk menulis range query, Anda membutuhkan Unix timestamps untuk awal dan akhir rentang. Unix timestamp converter membuat ini mudah — masukkan tanggalnya dan dapatkan timestampnya.

Berikut adalah perhitungan untuk pola query umum:

N hari terakhir: ` start = current_timestamp - (N × 86400) end = current_timestamp `

7 hari terakhir: start = now - 604800 (7 × 86.400 detik) 30 hari terakhir: start = now - 2592000 (30 × 86.400) 90 hari terakhir: start = now - 7776000

Bulan kalender tertentu (misalnya, Maret 2024): ` start = Unix timestamp dari 2024-03-01 00:00:00 UTC = 1709251200 end = Unix timestamp dari 2024-04-01 00:00:00 UTC = 1711929600 `

Query: WHERE created_at >= 1709251200 AND created_at < 1711929600

Catatan: gunakan < (kurang dari) bukan <= untuk batas akhir ketika menggunakan tengah malam hari berikutnya. Ini dengan bersih mengecualikan record apa pun dari 1 April tanpa perlu khawatir tentang detik terakhir yang tepat dari 31 Maret.

Year to date: ` start = Unix timestamp dari 1 Januari tahun ini, 00:00:00 UTC end = current timestamp `

Fixed date range antara dua tanggal: Konversi kedua tanggal ke UTC midnight timestamps menggunakan converter dan gunakan langsung sebagai batas.

Menangani Timezones dengan Benar

Kesalahan paling umum dengan Unix timestamp range queries adalah kebingungan timezone saat membuat boundary timestamps.

Unix timestamps selalu UTC. Jika aplikasi Anda perlu membuat query "order yang ditempatkan pada 8 April dalam New York time (UTC-4)," maka 8 April di New York mencakup:

  • 2024-04-08 00:00:00 EDT = 2024-04-08 04:00:00 UTC = Unix timestamp 1712545200
  • 2024-04-09 00:00:00 EDT = 2024-04-09 04:00:00 UTC = Unix timestamp 1712631600

Jika Anda naif menggunakan UTC midnight:

  • 2024-04-08 00:00:00 UTC = Unix timestamp 1712534400

Anda akan menyertakan 4 jam record dari akhir 7 April New York time, dan melewatkan 4 jam record dari akhir 8 April.

Pendekatan yang benar: selalu konversi date range Anda ke UTC sebelum membuat boundary timestamps. Dalam kode:

import datetime, pytz

tz = pytz.timezone('America/New_York')
start_local = tz.localize(datetime.datetime(2024, 4, 8, 0, 0, 0))
start_utc_ts = int(start_local.utctimetuple().tm_sec)  # atau .timestamp()

Atau gunakan date library yang menangani timezone-aware timestamps. Prinsip utamanya: buat batas dalam waktu lokal pengguna, konversi ke UTC, kemudian gunakan integer yang dihasilkan dalam query.

Indexing untuk Performa

Agar timestamp range queries cepat, timestamp column perlu memiliki index. Pada tabel dengan jutaan baris, unindexed integer scan untuk date range akan lambat terlepas dari betapa sederhananya query terlihat.

PostgreSQL: `sql CREATE INDEX idx_events_created_at ON events (created_at); `

MySQL: `sql ALTER TABLE events ADD INDEX idx_created_at (created_at); `

Untuk queries yang sering menggabungkan timestamp ranges dengan filter lain (misalnya, WHERE user_id = 123 AND created_at >= X), composite index dengan kolom paling selektif lebih dulu biasanya lebih cepat:

CREATE INDEX idx_events_user_created ON events (user_id, created_at);

Composite indexes memungkinkan database mempersempit berdasarkan user terlebih dahulu, kemudian hanya scan record terurut waktu user itu untuk rentangnya.

Membuat Timestamp Boundaries dalam Bahasa Pemrograman Umum

JavaScript: `javascript const now = Math.floor(Date.now() / 1000); const last30Days = now - (30 * 86400); // Query: WHERE created_at >= last30Days AND created_at <= now `

Python: `python import time now = int(time.time()) last_30_days = now - (30 * 86400) `

Untuk tanggal UTC tertentu: `python import datetime dt = datetime.datetime(2024, 1, 1, tzinfo=datetime.timezone.utc) ts = int(dt.timestamp()) # 1704067200 `

PHP: `php $now = time(); $start = mktime(0, 0, 0, 1, 1, 2024); // 1 Jan 2024 tengah malam waktu lokal // Gunakan strtotime untuk UTC: strtotime('2024-01-01 00:00:00 UTC') `

SQL (PostgreSQL) — membuat boundary inline: `sql SELECT * FROM events WHERE created_at >= EXTRACT(EPOCH FROM NOW() - INTERVAL '30 days')::int AND created_at <= EXTRACT(EPOCH FROM NOW())::int; `

Kesalahan Umum yang Harus Dihindari

Menggunakan local midnight bukan UTC midnight. Jika application server Anda berada di timezone berbeda dari UTC, new Date().setHours(0,0,0,0) di JavaScript memberi Anda tengah malam di timezone lokal server — bukan UTC. Selalu nyatakan timezone secara eksplisit.

Off-by-one pada batas akhir. created_at <= 1711929599 (detik terakhir 31 Maret) dan created_at < 1711929600 (tengah malam 1 April) setara, tetapi bentuk kedua lebih bersih dan menghindari edge case sub-second jika Anda pernah beralih ke milliseconds.

Lupa DST transitions. Ketika mengonversi date ranges dalam timezone dengan daylight saving time, satu hari per tahun adalah 23 jam dan satu lagi 25 jam. Ini mempengaruhi perhitungan "24 jam terakhir": now - 86400 tidak selalu "kemarin pada saat ini" dalam waktu lokal. Untuk query local-day yang presisi, buat batas dari tanggal kalender lokal secara eksplisit daripada mengurangi jumlah detik tetap.

Tidak mengindex timestamp column. Terlihat jelas dalam prinsip, tetapi sering kali terlewatkan dalam pengembangan awal ketika tabel kecil dan query lambat tidak diperhatikan.

Gunakan Unix timestamp converter untuk memverifikasi boundary timestamps Anda sebelum melayani query — tempel integernya dan konfirmasi konversi ke tanggal dan waktu yang Anda harapkan.

Artikel terkait