PostgreSQL
 sql >> Cơ Sở Dữ Liệu >  >> RDS >> PostgreSQL

Chuyển đổi giữa các múi giờ trong Postgres

Hãy để tôi giải thích hai ví dụ:

Trong cả hai, chúng tôi giả định múi giờ UTC (tức là SET timezone TO UTC ).

db=# SELECT timezone('US/Pacific', '2016-01-01 00:00');
      timezone
---------------------
 2015-12-31 16:00:00
(1 row)

Điều này tương đương với SELECT timezone('US/Pacific', '2016-01-01 00:00'::timestamptz) , tức là Postgres đã hoàn toàn chuyển đổi chuỗi thành timestamptz .

Chúng tôi biết rằng timezone hàm chuyển đổi qua lại giữa timestamptimestamptz :

Vì chúng tôi đang cung cấp cho nó một timestamptz dưới dạng đầu vào, nó sẽ xuất ra một timestamp . Nói cách khác, nó đang chuyển đổi điểm tuyệt đối trong thời gian 2016-01-01 00:00Z đến tận tường tại US/Pacific , tức là những gì đồng hồ ở Los Angeles hiển thị vào thời điểm tuyệt đối đó.

Trong ví dụ 2, chúng ta đang làm ngược lại, cụ thể là lấy timestamp và chuyển đổi nó thành timestamptz . Nói cách khác, chúng tôi đang hỏi:thời điểm tuyệt đối khi đồng hồ ở Los Angeles hiển thị 2016-01-01 00:00 là gì ?

Bạn đề cập:

'2016-01-01 00:00'::timestamptimestamp , tức là thời gian tường tận. Nó không có khái niệm về múi giờ.

Tôi nghĩ rằng bạn có thể chưa hiểu hết sự khác biệt giữa timestamptimestamptz , đó là chìa khóa ở đây. Chỉ nghĩ về chúng như là thời gian trên tường , tức là thời gian hiển thị ở đâu đó trên thế giới trên đồng hồ treo trên tường và thời gian tuyệt đối , tức là thời gian tuyệt đối trong vũ trụ của chúng ta.

Các ví dụ bạn đưa ra trong câu trả lời của riêng mình không hoàn toàn chính xác.

SELECT ts FROM  (VALUES
(timestamptz '2012-03-05 17:00:00+0') -- outputs 2012-03-05 17:00:00+00 --1
,(timestamptz '2012-03-05 18:00:00+1') -- outputs 2012-03-05 17:00:00+00 --2
,(timestamp   '2012-03-05 18:00:00+1') -- outputs 2012-03-05 18:00:00+00 --3
,(timestamp   '2012-03-05 11:00:00'  AT TIME ZONE '+6') -- outputs 2012-03-05 17:00:00+00 --4
,(timestamp   '2012-03-05 17:00:00'  AT TIME ZONE 'UTC') -- outputs 2012-03-05 17:00:00+00 --5
,(timestamp   '2012-03-05 17:00:00'::timestamp) -- outputs 2012-03-05 17:00:00+00 --6
,(timestamp   '2012-03-05 17:00:00'::timestamptz) -- outputs 2012-03-05 17:00:00+00 --7
    ) t(ts);

Vấn đề với ví dụ của bạn là bạn đang xây dựng một tập dữ liệu với một cột duy nhất. Vì một cột chỉ có thể có một loại, mỗi hàng (hoặc một giá trị trong trường hợp này) đang được chuyển đổi thành cùng một loại, cụ thể là timestamptz , mặc dù một số giá trị được tính dưới dạng timestamp (ví dụ:giá trị 3). Do đó, bạn có thêm một chuyển đổi ngầm ở đây.

Hãy chia ví dụ thành các truy vấn riêng biệt và xem điều gì đang xảy ra:

Ví dụ 1

db=# SELECT timestamptz '2012-03-05 17:00:00+0';
      timestamptz
------------------------
 2012-03-05 17:00:00+00

Như bạn có thể đã biết, timestamptz '2012-03-05 17:00:00+0''2012-03-05 17:00:00+0'::timestamptz là tương đương (tôi thích cái sau hơn). Vì vậy, chỉ cần sử dụng cùng một cú pháp như trong bài viết, tôi sẽ viết lại:

db=# SELECT '2012-03-05 17:00:00+0'::timestamptz;
      timestamptz
------------------------
 2012-03-05 17:00:00+00

Bây giờ, chuyện gì đang xảy ra ở đây? Chà, ít hơn trong lời giải thích ban đầu của bạn. Chuỗi chỉ được phân tích cú pháp dưới dạng timestamptz . Khi kết quả được in, nó sử dụng timezone hiện được đặt cấu hình để chuyển đổi nó trở lại dạng biểu diễn có thể đọc được của con người của cấu trúc dữ liệu cơ bản, tức là 2012-03-05 17:00:00+00 .

Hãy thay đổi timezone cấu hình và xem điều gì sẽ xảy ra:

db=# SET timezone TO 'Europe/Berlin';
SET
db=# SELECT '2012-03-05 17:00:00+0'::timestamptz;
      timestamptz
------------------------
 2012-03-05 18:00:00+01

Điều duy nhất đã thay đổi là cách timestamptz được in trên màn hình, cụ thể là sử dụng Châu Âu / Berlin múi giờ.

Ví dụ 2

db=# SELECT timestamptz '2012-03-05 18:00:00+1';
      timestamptz
------------------------
 2012-03-05 17:00:00+00
(1 row)

Một lần nữa, chỉ cần phân tích ngày.

Ví dụ 3

db=# SELECT timestamp '2012-03-05 18:00:00+1';
      timestamp
---------------------
 2012-03-05 18:00:00
(1 row)

Điều này giống với '2012-03-05 18:00:00+1'::timestamp . Điều xảy ra ở đây là độ lệch múi giờ đơn giản bị bỏ qua vì bạn đang yêu cầu timestamp .

Ví dụ 4

db=# SELECT timestamp '2012-03-05 11:00:00' AT TIME ZONE '+6';
        timezone
------------------------
 2012-03-05 17:00:00+00
(1 row)

Hãy viết lại để đơn giản hơn:

db=# SELECT timezone('+6', '2012-03-05 11:00:00'::timestamp);
        timezone
------------------------
 2012-03-05 17:00:00+00
(1 row)

Đây là câu hỏi:thời gian tuyệt đối khi đồng hồ trên tường ở múi giờ có độ lệch +6 giờ đang hiển thị 2012-03-05 11:00:00 ?

Ví dụ 5

db=# SELECT timestamp '2012-03-05 17:00:00' AT TIME ZONE 'UTC';
        timezone
------------------------
 2012-03-05 17:00:00+00
(1 row)

Hãy viết lại:

db=# SELECT timezone('UTC', '2012-03-05 17:00:00'::timestamp);
        timezone
------------------------
 2012-03-05 17:00:00+00
(1 row)

Đây là câu hỏi:thời gian tuyệt đối khi đồng hồ trên tường ở múi giờ UTC hiển thị 2012-03-05 17:00:00 ?

Ví dụ 6

db=# SELECT timestamp '2012-03-05 17:00:00'::timestamp;
      timestamp
---------------------
 2012-03-05 17:00:00
(1 row)

Ở đây bạn đang truyền hai lần tới timestamp , không có gì khác biệt. Hãy đơn giản hóa:

db=# SELECT '2012-03-05 17:00:00'::timestamp;
      timestamp
---------------------
 2012-03-05 17:00:00
(1 row)

Tôi nghĩ thế là rõ ràng.

Ví dụ 7

db=# SELECT timestamp '2012-03-05 17:00:00'::timestamptz;
      timestamptz
------------------------
 2012-03-05 17:00:00+00
(1 row)

Hãy viết lại:

db=# SELECT ('2012-03-05 17:00:00'::timestamp)::timestamptz;
      timestamptz
------------------------
 2012-03-05 17:00:00+00
(1 row)

Đầu tiên bạn phân tích chuỗi dưới dạng timestamp và sau đó chuyển đổi nó thành timestamptz sử dụng timezone hiện được đặt . Nếu chúng tôi thay đổi timezone , chúng tôi nhận được thứ khác vì Postgres giả định múi giờ đó khi chuyển đổi timestamp (hoặc một chuỗi thiếu thông tin múi giờ) thành timestamptz :

db=# SET timezone TO 'Europe/Berlin';
SET
db=# SELECT ('2012-03-05 17:00:00'::timestamp)::timestamptz;
      timestamptz
------------------------
 2012-03-05 17:00:00+01
(1 row)

Thời gian tuyệt đối này, được biểu thị bằng UTC, là 2012-03-05 16:00:00+00 , do đó khác với ví dụ ban đầu.

Tôi hy vọng điều này làm sáng tỏ mọi thứ. Một lần nữa, hãy hiểu sự khác biệt giữa timestamptimestamptz là chìa khóa. Hãy nghĩ về thời gian tường so với thời gian tuyệt đối.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Di chuyển quyền truy cập MS sang PostgreSQL

  2. Postgresql ĐẶT HÀNG THEO khoảng trắng

  3. hình học không được nhận dạng là tham số cho Find_SRID

  4. Nhận các phạm vi ngày liên tiếp khác nhau từ các phạm vi ngày trùng lặp

  5. PG ::ConnectionBad (FATAL:pg_hba.conf từ chối kết nối cho máy chủ 172.17.0.1, người dùng XXX, cơ sở dữ liệu XXX, tắt SSL):