Om du faktiskt har en kolumn av typen timestamp
och tolka den (i delar) beroende på den aktuella tidszonen, och denna tidszon kan variera, då är ett index i allmänhet omöjligt . Du kan bara bygga ett index på IMMUTABLE
data ...
Efter uppdatering:
För att svara på dessa frågor:
- Vilka bokningar börjar "idag"?
- Vilka bokningar har startdatum i framtiden?
- Vilka bokningar har tidigare startdatum?
... det är bäst att lagra en timestamp with time zone
. Bara ett date
är inte tillräckligt exakt.
Så länge vi bara är intresserade av det lokala "idag" (enligt definitionen av aktuell tidszon ), gör vi inte måste spara tidszonen explicit. Vi bryr oss inte om var i världen det händer, vi behöver bara en absolut tid att jämföra med.
Sedan, för att få bokningar från och med "idag" helt enkelt:
SELECT *
FROM reservations
WHERE start_on::date = current_date;
Men det här är inte sargbart
eftersom start_on::date
är ett härlett uttryck och vi kan inte heller bygga ett funktionellt index för detta (utan smutsiga trick) eftersom uttrycket beror på den aktuella tidszonen och inte är IMMUTABLE
.
Istället , jämför med början och slutet av "vår" dag i UTC-tid:
SELECT *
FROM reservations
WHERE start_on >= current_date::timestamptz
AND start_on < (current_date + 1)::timestamptz; -- exclude upper border
Nu kan detta enkla index stödja frågan:
CREATE INDEX ON reservations (start_on);
Demo
SQL Fiddle är nere i ATM. Här är en liten demo för att förstå:
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;
Mer förklaring och länkar här:
Ignorerar tidszoner helt och hållet i Rails och PostgreSQL