Jika Anda benar-benar memiliki kolom dengan tipe timestamp
dan menafsirkannya (sebagian) tergantung pada zona waktu saat ini, dan zona waktu ini dapat bervariasi, maka indeks umumnya tidak mungkin . Anda hanya dapat membuat indeks di IMMUTABLE
data ...
Setelah Pembaruan:
Untuk menjawab pertanyaan ini:
- Reservasi apa yang dimulai "hari ini"?
- Reservasi apa yang memiliki tanggal mulai di masa mendatang?
- Reservasi apa yang memiliki tanggal mulai di masa lalu?
... Anda sebaiknya menyimpan timestamp with time zone
. Hanya date
tidak cukup tepat.
Selama kita hanya tertarik pada "hari ini" lokal (sebagaimana didefinisikan oleh zona waktu saat ini ), kami tidak perlu menyimpan zona waktu secara eksplisit. Kami tidak peduli di dunia mana hal itu terjadi, kami hanya perlu waktu absolut untuk membandingkannya.
Kemudian, untuk mendapatkan reservasi mulai "hari ini" cukup:
SELECT *
FROM reservations
WHERE start_on::date = current_date;
Tapi ini tidak bisa dicela
karena start_on::date
adalah ekspresi turunan dan kami juga tidak dapat membangun indeks fungsional untuk ini, (tanpa trik kotor) karena ekspresi bergantung pada zona waktu saat ini dan bukan IMMUTABLE
.
Sebaliknya , bandingkan dengan awal dan akhir hari "kami" dalam waktu UTC:
SELECT *
FROM reservations
WHERE start_on >= current_date::timestamptz
AND start_on < (current_date + 1)::timestamptz; -- exclude upper border
Sekarang, indeks sederhana ini dapat mendukung kueri:
CREATE INDEX ON reservations (start_on);
Demo
SQL Fiddle sedang down ATM. Berikut adalah sedikit demo untuk membantu pemahaman:
CREATE TEMP TABLE reservations (
reservation_id serial
, start_on timestamptz NOT NULL
, time_zone text); -- we don't need this
INSERT INTO reservations (start_on, time_zone) VALUES
('2014-04-09 01:00+02', 'Europe/Vienna')
, ('2014-04-09 23:00+02', 'Europe/Vienna')
, ('2014-04-09 01:00+00', 'UTC') -- the value is independent of the time zone
, ('2014-04-09 23:00+00', 'UTC') -- only display depends on current time zone
, ('2014-04-09 01:00-07', 'America/Los_Angeles')
, ('2014-04-09 23:00-07', 'America/Los_Angeles');
SELECT start_on, time_zone
, start_on::timestamp AS local_ts
, start_on AT TIME ZONE time_zone AS ts_at_tz
, current_date::timestamptz AS lower_bound
, (current_date + 1)::timestamptz AS upper_bound
FROM reservations
WHERE start_on >= current_date::timestamptz
AND start_on < (current_date + 1)::timestamptz;
Penjelasan lebih lanjut dan tautan di sini:
Mengabaikan zona waktu sama sekali di Rails dan PostgreSQL