Ако действително имате колона от тип timestamp
и го интерпретира (на части) в зависимост от текущата часова зона и тази часова зона може да варира, тогава индексът обикновено е невъзможен . Можете да създадете индекс само върху IMMUTABLE
данни ...
След актуализация:
За да отговорите на тези въпроси:
- Какви резервации започват „днес“?
- Кои резервации имат начални дати в бъдеще?
- Кои резервации имат начални дати в миналото?
... най-добре съхранявайте timestamp with time zone
. Само date
не е достатъчно точен.
Докато се интересуваме само от местното „днес“ (както е определено от текущата часова зона ), ние го правимне трябва изрично да запазите часовата зона. Не ни интересува къде по света ще се случи, имаме нужда само от абсолютно време за сравнение.
След това, за да получите резервации, започващи „днес“, просто:
SELECT *
FROM reservations
WHERE start_on::date = current_date;
Но това не може да се копира
защото start_on::date
е производен израз и не можем да изградим функционален индекс и за него (без мръсни трикове), защото изразът зависи от текущата часова зона и не е IMMUTABLE
.
Вместо това , сравнете с началото и края на "нашия" ден в UTC време:
SELECT *
FROM reservations
WHERE start_on >= current_date::timestamptz
AND start_on < (current_date + 1)::timestamptz; -- exclude upper border
Сега този прост индекс може да поддържа заявката:
CREATE INDEX ON reservations (start_on);
Демо
SQL Fiddle не работи ATM. Ето малка демонстрация за разбиране:
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;
Повече обяснения и връзки тук:
Пълно игнориране на часовите зони в Rails и PostgreSQL