Pokud skutečně máte sloupec typu timestamp
a interpretovat jej (po částech) v závislosti na aktuálním časovém pásmu a toto časové pásmo se může lišit, pak je index obecně nemožný . Index můžete vytvořit pouze na IMMUTABLE
údaje ...
Po aktualizaci:
Chcete-li odpovědět na tyto otázky:
- Jaké rezervace začínají „dnes“?
- Jaké rezervace mají datum zahájení v budoucnosti?
- Jaké rezervace mají datum zahájení v minulosti?
... nejlépe uložte časové razítko timestamp with time zone
. Stačí date
není dostatečně přesný.
Dokud nás zajímá pouze místní „dnes“ (definované aktuálním časovým pásmem ), neděláme je třeba explicitně uložit časové pásmo. Je nám jedno, kde na světě se to stane, potřebujeme pouze absolutní čas na srovnání.
Poté, abyste získali rezervace počínaje „dnes“ jednoduše:
SELECT *
FROM reservations
WHERE start_on::date = current_date;
Ale toto nelze sargable
protože start_on::date
je odvozený výraz a ani pro to nemůžeme vytvořit funkční index (bez špinavých triků), protože výraz závisí na aktuálním časovém pásmu a není IMMUTABLE
.
Místo toho , porovnejte se začátkem a koncem „našeho“ dne v čase UTC:
SELECT *
FROM reservations
WHERE start_on >= current_date::timestamptz
AND start_on < (current_date + 1)::timestamptz; -- exclude upper border
Nyní tento jednoduchý index může podporovat dotaz:
CREATE INDEX ON reservations (start_on);
Ukázka
SQL Fiddle je mimo provoz bankomatu. Zde je malá ukázka, která vám pomůže pochopit:
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;
Další vysvětlení a odkazy zde:
Úplné ignorování časových pásem v Rails a PostgreSQL