Làm cách nào để có được dấu thời gian unix hiện tại từ PostgreSQL?


91

Dấu thời gian Unix là số giây kể từ nửa đêm UTC ngày 1 tháng 1 năm 1970.

Làm cách nào để có được dấu thời gian unix chính xác từ PostgreSQL?

Khi so sánh với currenttimestamp.comtimestamp.1e5b.de Tôi không nhận được thời gian mong đợi từ PostgreQuery:

Điều này trả về dấu thời gian chính xác:

SELECT extract(epoch from now());

Trong khi điều này không:

SELECT extract(epoch from now() at time zone 'utc');

Tôi sống ở múi giờ UTC +02. Cách chính xác để có được dấu thời gian unix hiện tại từ PostgreSQL là gì?

Điều này trả về đúng thời gian và múi giờ:

SELECT now();
              now
-------------------------------
 2011-05-18 10:34:10.820464+02

Một so sánh khác:

select now(), 
extract(epoch from now()), 
extract(epoch from now() at time zone 'utc');
              now              |    date_part     |    date_part
-------------------------------+------------------+------------------
 2011-05-18 10:38:16.439332+02 | 1305707896.43933 | 1305700696.43933
(1 row)

Unix timestamp from the web sites:
1305707967

Câu trả lời:


82

Trong postgres, timestamp with time zonecó thể được viết tắt là timestamptz, và timestamp without time zonenhư timestamp. Tôi sẽ sử dụng tên loại ngắn hơn để đơn giản.

Lấy dấu thời gian Unix từ một postgres timestamptznhư now()đơn giản, như bạn nói, chỉ cần:

select extract(epoch from now());

Đó thực sự là tất cả những gì bạn cần biết về việc có được thời gian tuyệt đối từ bất cứ thứ gì thuộc loại timestamptz, kể cả now().

Mọi thứ chỉ trở nên phức tạp khi bạn có một timestamplĩnh vực.

Khi bạn đặt timestamptzdữ liệu như now()vào trường đó, trước tiên nó sẽ được chuyển đổi thành múi giờ cụ thể (rõ ràng bằng at time zonehoặc chuyển đổi sang múi giờ phiên) và thông tin múi giờ bị loại bỏ . Nó không còn đề cập đến một thời gian tuyệt đối. Đây là lý do tại sao bạn thường không muốn lưu trữ dấu thời gian như timestampthường sử dụng timestamptz- có thể một bộ phim được phát hành vào lúc 6 giờ tối vào một ngày cụ thể trong mỗi múi giờ , đó là loại trường hợp sử dụng.

Nếu bạn chỉ làm việc trong một múi giờ duy nhất, bạn có thể thoát khỏi (mis) bằng cách sử dụng timestamp. Chuyển đổi trở lại timestamptzđủ thông minh để đối phó với DST và dấu thời gian được giả định, cho mục đích chuyển đổi, nằm trong múi giờ hiện tại. Đây là một ví dụ cho GMT / BST:

select '2011-03-27 00:59:00.0+00'::timestamptz::timestamp::timestamptz
     , '2011-03-27 01:00:00.0+00'::timestamptz::timestamp::timestamptz;

/*
|timestamptz           |timestamptz           |
|:---------------------|:---------------------|
|2011-03-27 00:59:00+00|2011-03-27 02:00:00+01|
*/

DBFiddle

Nhưng, lưu ý hành vi khó hiểu sau đây:

set timezone to 0;

values(1, '1970-01-01 00:00:00+00'::timestamp::timestamptz)
    , (2, '1970-01-01 00:00:00+02'::timestamp::timestamptz);

/*
|column1|column2               |
|------:|:---------------------|
|      1|1970-01-01 00:00:00+00|
|      2|1970-01-01 00:00:00+00|
*/

DBFiddle

Điều này là do :

PostgreQuery không bao giờ kiểm tra nội dung của một chuỗi ký tự trước khi xác định loại của nó và do đó sẽ coi cả [[]] là dấu thời gian không có múi giờ. Để đảm bảo rằng một chữ được coi là dấu thời gian với múi giờ, hãy đặt cho nó một kiểu rõ ràng chính xác Trong một chữ được xác định là dấu thời gian không có múi giờ, PostgreQuery sẽ âm thầm bỏ qua bất kỳ dấu hiệu múi giờ nào


Mọi ý tưởng làm thế nào để chuyển đổi số thập phân kết quả thành một số nguyên không có dấu thập phân (ý tôi là hợp nhất số và số thập phân thành một số nguyên lớn). Cảm ơn.
WM

Thích điều này nhưng tôi chắc chắn bạn không thực sự muốn làm điều đó. Có lẽ bạn muốn nhân với một sức mạnh mười và tước bất kỳ số thập phân nào còn lại?
Jack Douglas

2
@WM Có lẽ như thế này? SELECT FLOOR(EXTRACT(epoch FROM NOW())*1000);
Joe23

21
SELECT extract(epoch from now() at time zone 'utc');

không trả về dấu thời gian chính xác vì chuyển đổi múi giờ sau đó loại bỏ thông tin múi giờ khỏi kết quả:

9.9.3. TẠI KHU THỜI GIAN

Cú pháp: dấu thời gian không có múi giờ AT múi giờ TIME
Trả về: dấu thời gian với múi giờ
Xử lý dấu thời gian đã cho mà không có múi giờ như trong múi giờ đã chỉ định

Cú pháp: dấu thời gian với múi giờ AT múi giờ TIME
Trả về: dấu thời gian không có múi giờ
Chuyển đổi dấu thời gian đã cho với múi giờ sang múi giờ mới, không có chỉ định múi giờ

sau đó, trích xuất xem dấu thời gian mà không có múi giờ và coi đó là giờ địa phương (mặc dù thực tế nó đã là utc).

Cách chính xác sẽ là:

select now(),
       extract(epoch from now()),                                          -- correct
       extract(epoch from now() at time zone 'utc'),                       -- incorrect
       extract(epoch from now() at time zone 'utc' at time zone 'utc');    -- correct

          now                  |    date_part     |    date_part     |    date_part
-------------------------------+------------------+------------------+------------------
 2014-10-14 10:19:23.726908+02 | 1413274763.72691 | 1413267563.72691 | 1413274763.72691
(1 row)

Trong dòng cuối cùng, lần đầu tiên at time zonethực hiện chuyển đổi, dòng thứ hai gán múi giờ mới cho kết quả.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.