Kiểu dữ liệu timestamp
là tên viết tắt của timestamp without time zone
.
Các tùy chọn khác timestamptz
là viết tắt của timestamp with time zone
.
timestamptz
là loại ưa thích trong gia đình ngày / giờ, theo nghĩa đen. Nó đã typispreferred
được thiết lập pg_type
, có thể có liên quan:
Trong nội bộ, dấu thời gian chiếm 8 byte lưu trữ trên đĩa và trong RAM. Đó là một giá trị số nguyên biểu thị số micrô giây từ kỷ nguyên Postgres, 2000-01-01 00:00:00 UTC.
Postgres cũng có kiến thức tích hợp về thời gian UNIX thường được sử dụng tính từ giây UNIX, 1970-01-01 00:00:00 UTC và sử dụng chức năng đó trong các chức năng to_timestamp(double precision)
hoặc EXTRACT(EPOCH FROM timestamptz)
.
Mã nguồn:
* Dấu thời gian, cũng như các trường h / m / s của các khoảng, được lưu trữ dưới dạng
* giá trị int64 với đơn vị micro giây. (Ngày xửa ngày xưa
* giá trị gấp đôi với đơn vị giây.)
Và:
/ * Tương đương ngày Julian của Ngày 0 trong Unix và Postgres tính toán * /
#define UNIX_EPOCH_JDATE 2440588 / * == date2j (1970, 1, 1) * /
#define POSTGRES_EPOCH_JDATE 2451545 / * == date2j (2000, 1, 1) * /
Độ phân giải micro giây chuyển thành tối đa 6 chữ số phân số trong vài giây.
timestamp
Một giá trị được gõ như nói với Postgres rằng không có múi giờ nào được cung cấp rõ ràng. Múi giờ hiện tại được giả định. Postgres bỏ qua bất kỳ sửa đổi múi giờ được thêm vào do nhầm lẫn!timestamp
[without time zone]
Không có giờ được thay đổi để hiển thị. Với cùng một cài đặt múi giờ, tất cả đều ổn. Đối với cài đặt múi giờ khác, ý nghĩa thay đổi, nhưng giá trị và hiển thị giữ nguyên.
timestamptz
Xử lý timestamp with time zone
là khác nhau tinh tế. Tôi trích dẫn hướng dẫn ở đây :
Đối với timestamp with time zone
, giá trị được lưu trữ nội bộ luôn ở UTC (Giờ phối hợp toàn cầu ...)
Nhấn mạnh đậm của tôi. Các múi giờ riêng của mình là không bao giờ được lưu trữ . Nó là một công cụ sửa đổi đầu vào được sử dụng để tính toán dấu thời gian theo UTC, được lưu trữ - hoặc và công cụ sửa đổi đầu ra được sử dụng để tính thời gian cục bộ để hiển thị - với độ lệch múi giờ được nối thêm. Nếu bạn không nối phần bù cho timestamptz
đầu vào, cài đặt múi giờ hiện tại của phiên được giả định. Tất cả các tính toán được thực hiện với các giá trị dấu thời gian UTC. Nếu bạn phải (hoặc có thể phải) đối phó với nhiều hơn một múi giờ, hãy sử dụng timestamptz
.
Các máy khách như psql hoặc pgAdmin hoặc bất kỳ ứng dụng nào giao tiếp qua libpq (như Ruby với đá quý pg) được hiển thị với dấu thời gian cộng với bù cho múi giờ hiện tại hoặc theo múi giờ được yêu cầu (xem bên dưới). Nó luôn luôn là cùng một thời điểm , chỉ có định dạng hiển thị khác nhau. Hoặc, như hướng dẫn đặt nó :
Tất cả các ngày và giờ nhận biết múi giờ được lưu trữ nội bộ trong UTC. Chúng được chuyển đổi thành giờ địa phương trong vùng được chỉ định bởi
tham số cấu hình TimeZone trước khi được hiển thị cho máy khách.
Hãy xem xét ví dụ đơn giản này (trong psql):
db = # CHỌN dấu thời gian ' 2012 / 03-05 20:00 +03 ';
dấu thời gian
------------------------
2012 / 03-05 18:00:00 +01
Nhấn mạnh đậm của tôi. Chuyện gì đã xảy ra ở đây?
Tôi đã chọn một bù múi giờ tùy ý +3
cho chữ đầu vào. Đối với Postgres, đây chỉ là một trong nhiều cách để nhập dấu thời gian UTC 2012-03-05 17:00:00
. Kết quả của truy vấn được hiển thị cho cài đặt múi giờ hiện tại Vienna / Áo trong thử nghiệm của tôi, có phần bù +1
trong mùa đông và +2
trong thời gian mùa hè : 2012-03-05 18:00:00+01
, vì nó rơi vào thời điểm mùa đông.
Postgres đã quên cách nhập giá trị này. Tất cả những gì nó nhớ là giá trị và kiểu dữ liệu. Giống như với một số thập phân. numeric '003.4'
, numeric '3.40'
Hoặc numeric '+3.4'
- tất cả các kết quả về giá trị nội bộ cùng chính xác.
AT TIME ZONE
Ngay khi bạn nắm bắt được logic này, bạn có thể làm bất cứ điều gì bạn muốn. Tất cả những gì còn thiếu bây giờ, là một công cụ để giải thích hoặc biểu thị các ký tự dấu thời gian theo một múi giờ cụ thể. Đó là nơi mà AT TIME ZONE
cấu trúc xuất hiện. Có hai trường hợp sử dụng khác nhau. timestamptz
được chuyển đổi thành timestamp
và ngược lại.
Để vào UTC timestamptz
2012-03-05 17:00:00+0
:
SELECT timestamp '2012-03-05 17:00:00' AT TIME ZONE 'UTC'
... tương đương với:
SELECT timestamptz '2012-03-05 17:00:00 UTC'
Để hiển thị cùng thời điểm với EST timestamp
(Giờ chuẩn miền đông):
SELECT timestamp '2012-03-05 17:00:00' AT TIME ZONE 'UTC' AT TIME ZONE 'EST'
Điều đó đúng, AT TIME ZONE 'UTC'
hai lần . Cái đầu tiên diễn giải timestamp
giá trị là dấu thời gian UTC (đã cho) trả về kiểu timestamptz
. Điều thứ hai chuyển đổi timestamptz
sang timestamp
theo múi giờ cho 'EST' - những gì một chiếc đồng hồ trong thời gian hiển thị khu EST vào thời điểm đặc biệt này trong thời gian.
Ví dụ
SELECT ts AT TIME ZONE 'UTC'
FROM (
VALUES
(1, timestamptz '2012-03-05 17:00:00+0')
, (2, timestamptz '2012-03-05 18:00:00+1')
, (3, timestamptz '2012-03-05 17:00:00 UTC')
, (4, timestamp '2012-03-05 11:00:00' AT TIME ZONE '+6')
, (5, timestamp '2012-03-05 17:00:00' AT TIME ZONE 'UTC')
, (6, timestamp '2012-03-05 07:00:00' AT TIME ZONE 'US/Hawaii') -- ①
, (7, timestamptz '2012-03-05 07:00:00 US/Hawaii') -- ①
, (8, timestamp '2012-03-05 07:00:00' AT TIME ZONE 'HST') -- ①
, (9, timestamp '2012-03-05 18:00:00+1') -- ② loaded footgun!
) t(id, ts);
Trả về 8 (hoặc 9) hàng giống hệt nhau với các cột dấu thời gian giữ cùng dấu thời gian UTC 2012-03-05 17:00:00
. Hàng thứ 9 xảy ra để hoạt động trong múi giờ của tôi, nhưng là một cái bẫy xấu xa. Xem bên dưới.
Hàng 6 - 8 với tên múi giờ và viết tắt múi giờ cho giờ Hawaii phải tuân theo DST (thời gian tiết kiệm ánh sáng ban ngày) và có thể khác nhau, mặc dù hiện tại không. Tên múi giờ giống như 'US/Hawaii'
nhận thức được các quy tắc DST và tất cả các thay đổi lịch sử tự động, trong khi tên viết tắt giống như HST
chỉ là một mã câm cho phần bù cố định. Bạn có thể cần phải viết thêm một chữ viết tắt khác cho mùa hè / giờ chuẩn. Các tên giải thích một cách chính xác bất kỳ dấu thời gian tại các múi giờ nhất định. Một chữ viết tắt là rẻ, nhưng cần phải là chữ viết đúng cho dấu thời gian đã cho:
Giờ tiết kiệm ánh sáng ban ngày không phải là một trong những ý tưởng sáng chói nhất mà nhân loại từng nghĩ ra.
② Row 9, đánh dấu là footgun tải làm việc cho tôi , nhưng chỉ bằng cách trùng hợp ngẫu nhiên. Nếu bạn sử dụng một cách rõ ràng theo nghĩa đen timestamp [without time zone]
, bất kỳ khoảng thời gian nào đều bị bỏ qua ! Chỉ có dấu thời gian trần được sử dụng. Giá trị sau đó được tự động ép buộc timestamptz
trong ví dụ để khớp với loại cột. Đối với bước này, timezone
cài đặt của phiên hiện tại được giả sử, đó là cùng múi giờ +1
trong trường hợp của tôi (Châu Âu / Vienna). Nhưng có lẽ không phải trong trường hợp của bạn - sẽ dẫn đến một giá trị khác. Nói tóm lại: Đừng bỏ timestamptz
chữ timestamp
hoặc bạn mất phần bù múi giờ.
Những câu hỏi của bạn
Người dùng lưu trữ một thời gian, giả sử ngày 17 tháng 3 năm 2012, 7 giờ tối. Tôi không muốn chuyển đổi múi giờ hoặc múi giờ được lưu trữ.
Múi giờ chính nó không bao giờ được lưu trữ. Sử dụng một trong các phương pháp trên để nhập dấu thời gian UTC.
Tôi chỉ sử dụng múi giờ do người dùng chỉ định để nhận bản ghi 'trước' hoặc 'sau' thời gian hiện tại trong múi giờ địa phương của người dùng.
Bạn có thể sử dụng một truy vấn cho tất cả khách hàng ở các múi giờ khác nhau.
Đối với thời gian toàn cầu tuyệt đối:
SELECT * FROM tbl WHERE time_col > (now() AT TIME ZONE 'UTC')::time
Đối với thời gian theo đồng hồ địa phương:
SELECT * FROM tbl WHERE time_col > now()::time
Không mệt mỏi với thông tin cơ bản, chưa? Có nhiều hơn trong hướng dẫn.