Nếu bạn thực sự có một cột thuộc loại timestamp
và diễn giải nó (theo từng phần) tùy thuộc vào múi giờ hiện tại và múi giờ này có thể thay đổi, khi đó một chỉ mục nói chung là không thể . Bạn chỉ có thể tạo chỉ mục trên IMMUTABLE
dữ liệu ...
Sau khi cập nhật:
Để trả lời những câu hỏi này:
- Đặt chỗ nào sẽ bắt đầu "hôm nay"?
- Đặt chỗ nào có ngày bắt đầu trong tương lai?
- Đặt chỗ nào có ngày bắt đầu trong quá khứ?
... tốt nhất bạn nên lưu trữ timestamp with time zone
. Chỉ là một date
không đủ chính xác.
Miễn là chúng tôi chỉ quan tâm đến địa phương "hôm nay" (như được xác định bởi múi giờ hiện tại ), chúng tôi không cần lưu múi giờ một cách rõ ràng. Chúng tôi không quan tâm điều đó xảy ra ở đâu trên thế giới, chúng tôi chỉ cần một khoảng thời gian tuyệt đối để so sánh với.
Sau đó, để nhận đặt chỗ bắt đầu từ "hôm nay", chỉ cần:
SELECT *
FROM reservations
WHERE start_on::date = current_date;
Nhưng đây là không thể phân loại
bởi vì start_on::date
là một biểu thức dẫn xuất và chúng tôi cũng không thể xây dựng một chỉ mục chức năng cho điều này, (không có các thủ thuật bẩn) vì biểu thức phụ thuộc vào múi giờ hiện tại và không phải là IMMUTABLE
.
Thay vào đó , so sánh với thời điểm bắt đầu và kết thúc ngày của "chúng ta" theo giờ UTC:
SELECT *
FROM reservations
WHERE start_on >= current_date::timestamptz
AND start_on < (current_date + 1)::timestamptz; -- exclude upper border
Bây giờ, chỉ mục đơn giản này có thể hỗ trợ truy vấn:
CREATE INDEX ON reservations (start_on);
Bản trình diễn
SQL Fiddle ngừng hoạt động ATM. Dưới đây là một bản demo nhỏ để giúp bạn hiểu:
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;
Giải thích thêm và liên kết ở đây:
Bỏ qua hoàn toàn các múi giờ trong Rails và PostgreSQL