Có vẻ như bạn muốn lưu trữ một localtime đối với một múi giờ nhất định. Trong trường hợp đó, hãy lưu trữ timestamp
(không có múi giờ) và timezone
trong một cột riêng biệt.
Ví dụ:giả sử bạn muốn ghi lại một sự kiện sẽ xảy ra lúc 10 giờ sáng ngày 26 tháng 2 năm 2030 ở Chicago và nó phải là 10 giờ sáng giờ địa phương bất kể quy tắc múi giờ có hiệu lực vào ngày đó.
Nếu cơ sở dữ liệu lưu trữ dấu thời gian không có múi giờ:
unutbu=# select '2030-02-26 10:00:00'::timestamp as localtime, 'America/Chicago' AS tzone;
+---------------------+-----------------+
| localtime | tzone |
+---------------------+-----------------+
| 2030-02-26 10:00:00 | America/Chicago |
+---------------------+-----------------+
Sau đó, bạn có thể tìm ngày giờ UTC của sự kiện bằng cách sử dụng
unutbu=# select '2030-02-26 10:00:00'::timestamp AT TIME ZONE 'America/Chicago' AT TIME ZONE 'UTC';
+---------------------+
| timezone |
+---------------------+
| 2030-02-26 16:00:00 |
+---------------------+
Truy vấn trả về ngày giờ UTC, 2030-02-26 16:00:00
, tương ứng với 2030-02-26 10:00:00
giờ địa phương ở Chicago.
Sử dụng AT TIME ZONE
trì hoãn việc áp dụng các quy tắc múi giờ khi truy vấn được thực hiện thay vì khi timestamptz
đã được chèn.
Sử dụng AT TIME ZONE
trên timestamp
bản địa hóa ngày giờ thành múi giờ nhất định, nhưng báo cáo ngày giờ trong múi giờ của người dùng .Sử dụng AT TIME ZONE
trên timestamptz
chuyển đổi ngày giờ thành múi giờ nhất định, sau đó giảm độ lệch, do đó trả về timestamp
.Above, AT TIME ZONE
được sử dụng hai lần:lần đầu tiên để bản địa hóa timestamp
và tiếp theo để chuyển đổi timestamptz
được trả về sang múi giờ mới (UTC). Kết quả là một timestamp
theo giờ UTC.
Đây là một ví dụ minh họa AT TIME ZONE
hành vi của timestamp
s:
unutbu=# SET timezone = 'America/Chicago';
unutbu=# SELECT '2030-02-26 10:00:00'::timestamp AT TIME ZONE 'America/Chicago';
+------------------------+
| timezone |
+------------------------+
| 2030-02-26 10:00:00-06 |
+------------------------+
unutbu=# SET timezone = 'America/Los_Angeles';
unutbu=# SELECT '2030-02-26 10:00:00'::timestamp AT TIME ZONE 'America/Chicago';
+------------------------+
| timezone |
+------------------------+
| 2030-02-26 08:00:00-08 |
+------------------------+
2030-02-26 10:00:00-06
và 2030-02-26 08:00:00-08
là cùng ngày giờ nhưng được báo cáo theo múi giờ của người dùng khác nhau. Điều này cho thấy 10 giờ sáng ở Chicago là 8 giờ sáng ở Los Angeles (sử dụng định nghĩa múi giờ hiện tại):
unutbu=# SELECT '2030-02-26 10:00:00-06'::timestamptz AT TIME ZONE 'America/Los_Angeles';
+---------------------+
| timezone |
+---------------------+
| 2030-02-26 08:00:00 |
+---------------------+
Một giải pháp thay thế cho việc sử dụng AT TIME ZONE
hai lần là đặt múi giờ của người dùng
sang UTC
. Sau đó, bạn có thể sử dụng
select localtime AT TIME ZONE tzone
Lưu ý rằng khi thực hiện theo cách này, timestamptz
được trả lại thay vì timestamp
.
Lưu ý rằng việc lưu trữ thời gian cục bộ có thể có vấn đề vì có thể có thời gian không tồn tại và thời gian không rõ ràng. Ví dụ:2018-03-11 02:30:00
là giờ địa phương không tồn tại ở America/Chicago
. Postgresql chuẩn hóa thời gian cục bộ không tồn tại bằng cách giả sử nó đề cập đến thời gian tương ứng sau khi Giờ tiết kiệm ánh sáng ban ngày (DST) bắt đầu (như thể ai đó quên đặt đồng hồ của họ về phía trước):
unutbu=# select '2018-03-11 02:30:00'::timestamp AT TIME ZONE 'America/Chicago' AT TIME ZONE 'UTC';
+---------------------+
| timezone |
+---------------------+
| 2018-03-11 08:30:00 |
+---------------------+
(1 row)
unutbu=# select '2018-03-11 03:30:00'::timestamp AT TIME ZONE 'America/Chicago' AT TIME ZONE 'UTC';
+---------------------+
| timezone |
+---------------------+
| 2018-03-11 08:30:00 |
+---------------------+
(1 row)
Ví dụ về localtime không rõ ràng là 2018-11-04 01:00:00
ở America/Chicago
. Nó xảy ra hai lần do DST. Postgresql giải quyết sự không rõ ràng này bằng cách chọn thời gian muộn hơn, sau khi DST kết thúc:
unutbu=# select '2018-11-04 01:00:00'::timestamp AT TIME ZONE 'America/Chicago' AT TIME ZONE 'UTC';
+---------------------+
| timezone |
+---------------------+
| 2018-11-04 07:00:00 |
+---------------------+
Lưu ý rằng điều này có nghĩa là không có cách nào để tham chiếu đến 2018-11-04 06:00:00 UTC
bằng cách lưu trữ giờ địa phương ở America/Chicago
múi giờ:
unutbu=# select '2018-11-04 00:59:59'::timestamp AT TIME ZONE 'America/Chicago' AT TIME ZONE 'UTC';
+---------------------+
| timezone |
+---------------------+
| 2018-11-04 05:59:59 |
+---------------------+