PostgreSQL 中帶和不帶時區的時間戳之間的區別

Shihab Sikder 2023年1月30日
  1. PostgreSQL 中的時間戳
  2. PostgreSQL 中帶和不帶時區的時間戳之間的區別
PostgreSQL 中帶和不帶時區的時間戳之間的區別

本教程將討論 PostgreSQL 中的時間戳型別並展示它們的區別。

PostgreSQL 中的時間戳

在 PostgreSQL 中,有兩種型別的時間戳。

  1. 沒有時區的時間戳
  2. 帶時區的時間戳

第一個儲存本地日期。例如,假設現在是 24 小時系統時鐘中的 11.00。

因此,這將儲存為 11.00。如果它儲存在資料庫中,比如遠端資料庫中,並且有人從 CST 時區拉出這一行,他仍會將其視為 11.00。

然而,這不是真正的時間。檢視該時間所需的 CST 將轉換為 CST 時區。

由於它不儲存有關時區的任何資訊,因此無法在不同時區進一步確定。

第二種方法解決了這個問題。因此,每當你在資料庫中推送時間戳時,它都會從主機系統中提取時區並將時區與時間戳一起儲存。

假設我們在 GMT+6 時區。這是時間戳的演示。

SELECT now() as "System Time",
now()::timestamp as "postgres Time",
now() AT TIME ZONE 'GMT' as "time without zone",
now() AT TIME ZONE 'CST' as "time without zone",
now()::timestamp at TIME ZONE 'GMT' as "Timestamp GMT",
now()::timestamp at TIME ZONE 'CST' as "Timestamp CST" ;

這裡,第一列包含系統時間,第二列包含將時間轉換為不帶時區的時間戳後的時間戳。

輸出:

          System Time          |       postgres Time        |     time without zone      |     time without zone      |         Timestamp GMT         |         Timestamp CST
-------------------------------+----------------------------+----------------------------+----------------------------+-------------------------------+-------------------------------
 2022-03-15 10:19:05.432758+06 | 2022-03-15 10:19:05.432758 | 2022-03-15 04:19:05.432758 | 2022-03-14 22:19:05.432758 | 2022-03-15 16:19:05.432758+06 | 2022-03-15 22:19:05.432758+06
(1 row)

PostgreSQL 中帶和不帶時區的時間戳之間的區別

讓我們建立一個表,看看它如何儲存時間戳,以及如何在 PostgreSQL 中使用無時區有時區

首先,將你的 psql 控制檯連線到 Postgres,然後執行以下 SQL 命令來建立如下表:

CREATE TABLE Times(
    id INT PRIMARY KEY NOT NULL,
    time_without_zone TIMESTAMP WITHOUT TIME ZONE DEFAULT now(),
    time_with_zone TIMESTAMP WITH TIME ZONE DEFAULT now()
);

現在,用一些條目填充表。

INSERT INTO Times(id) VALUES(1);
INSERT INTO Times(id) VALUES(2);
INSERT INTO Times(id) VALUES(3);
INSERT INTO Times(id) VALUES(4);
INSERT INTO Times(id) VALUES(5);
INSERT INTO Times(id) VALUES(6);
INSERT INTO Times(id) VALUES(7);

輸出:

postgres=# select * from times;
 id |     time_without_zone      |        time_with_zone
----+----------------------------+-------------------------------
  1 | 2022-03-15 10:29:03.52078  | 2022-03-15 10:29:03.52078+06
  2 | 2022-03-15 10:29:03.52564  | 2022-03-15 10:29:03.52564+06
  3 | 2022-03-15 10:29:03.526723 | 2022-03-15 10:29:03.526723+06
  4 | 2022-03-15 10:29:03.527775 | 2022-03-15 10:29:03.527775+06
  5 | 2022-03-15 10:29:03.528865 | 2022-03-15 10:29:03.528865+06
  6 | 2022-03-15 10:29:03.529941 | 2022-03-15 10:29:03.529941+06
  7 | 2022-03-15 10:29:05.045774 | 2022-03-15 10:29:05.045774+06
(7 rows)

postgres=#

如你所見,time_with_zone 列儲存帶有 GMT+06 時區的時間。時間可以轉換為任何其他時區,因為 psql 將知道列中時間的基數。

這是一個示例輸出,它顯示瞭如果你嘗試在沒有時區型別的列上插入帶有時區的時間戳會發生什麼。

INSERT INTO Times(id,time_without_zone,time_with_zone) VALUES(9,'2022-03-15 10:29:05.045774+06','2022-03-15 10:29:05.045774+06');

輸出:

postgres=# select * from times where id=9;
 id |     time_without_zone      |        time_with_zone
----+----------------------------+-------------------------------
  9 | 2022-03-15 10:29:05.045774 | 2022-03-15 10:29:05.045774+06
(1 row)

如你所見,psql 只是在 time_without_zone 列中刪除了 +06。

如果要檢視 Postgres 中所有可用的時區,可以執行以下 SQL 命令:

postgres=# SELECT name FROM pg_timezone_names;
               name
----------------------------------
 Africa/Abidjan
 Africa/Accra
 Africa/Addis_Ababa
 Africa/Algiers
 Africa/Asmara
 Africa/Asmera
 Africa/Bamako
 Africa/Bangui
 Africa/Banjul
 Africa/Bissau
 -- More --

此處,系統在 GMT+6 時區執行。如果要將 Postgres 時區更改為其他時區,可以執行以下命令:

postgres=# SET TIMEZONE='UTC';
SET

如果你看到上表的資料,你會看到帶有時區的列已成功轉換為 UTC。

postgres=# select * from times;
 id |     time_without_zone      |        time_with_zone
----+----------------------------+-------------------------------
  1 | 2022-03-15 10:29:03.52078  | 2022-03-15 04:29:03.52078+00
  2 | 2022-03-15 10:29:03.52564  | 2022-03-15 04:29:03.52564+00
  3 | 2022-03-15 10:29:03.526723 | 2022-03-15 04:29:03.526723+00
  4 | 2022-03-15 10:29:03.527775 | 2022-03-15 04:29:03.527775+00
  5 | 2022-03-15 10:29:03.528865 | 2022-03-15 04:29:03.528865+00
  6 | 2022-03-15 10:29:03.529941 | 2022-03-15 04:29:03.529941+00
  7 | 2022-03-15 10:29:05.045774 | 2022-03-15 04:29:05.045774+00
  9 | 2022-03-15 10:29:05.045774 | 2022-03-15 04:29:05.045774+00
(8 rows)

你可以看到 time_without_zone 保持不變,但 time_with_zone 從 GMT+06 轉換為 UTC。要了解有關時間戳格式和表示的更多資訊,請訪問官方文件

作者: Shihab Sikder
Shihab Sikder avatar Shihab Sikder avatar

I'm Shihab Sikder, a professional Backend Developer with experience in problem-solving and content writing. Building secure, scalable, and reliable backend architecture is my motive. I'm working with two companies as a part-time backend engineer.

LinkedIn Website