ฉันจะรับการประทับเวลา unix ปัจจุบันจาก PostgreSQL ได้อย่างไร


91

Unix timestampคือจำนวนวินาทีตั้งแต่เที่ยงคืน UTC 1 มกราคม 1970

ฉันจะรับการประทับเวลา unix ที่ถูกต้องจาก PostgreSQL ได้อย่างไร

เมื่อเปรียบเทียบกับcurrenttimestamp.comและtimestamp.1e5b.deฉันไม่ได้รับเวลาที่คาดหวังจาก PostgreSQL:

ส่งคืนการประทับเวลาที่ถูกต้อง:

SELECT extract(epoch from now());

ในขณะนี้ไม่ได้:

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

ฉันอาศัยอยู่ในเขตเวลา UTC +02 วิธีที่ถูกต้องในการรับ timestamp ยูนิกซ์ปัจจุบันจาก PostgreSQL คืออะไร?

สิ่งนี้จะคืนค่าเวลาและโซนเวลาที่ถูกต้อง:

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

การเปรียบเทียบอื่น:

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

คำตอบ:


82

ใน postgres, timestamp with time zoneสามารถย่อเป็นtimestamptzและเป็นtimestamp without time zone timestampฉันจะใช้ชื่อประเภทสั้นลงเพื่อความเรียบง่าย

การรับ Unix timestamp จาก postgres timestamptzlike now()นั้นง่ายอย่างที่คุณพูดเพียง:

select extract(epoch from now());

ที่จริงสิ่งที่คุณจำเป็นต้องรู้เกี่ยวกับการรับเวลาที่แน่นอนจากสิ่งที่ประเภทรวมทั้งtimestamptznow()

สิ่งที่ซับซ้อนเมื่อคุณมีtimestampเขตข้อมูลเท่านั้น

เมื่อคุณใส่timestamptzข้อมูลเช่นnow()เข้าไปในสนามว่ามันจะเป็นครั้งแรกถูกแปลงเป็นเขตเฉพาะ (อย่างใดอย่างหนึ่งอย่างชัดเจนด้วยat time zoneหรือโดยการแปลงเขตเวลาเซสชั่น) และข้อมูลเขตเวลาจะถูกยกเลิก มันไม่ได้หมายถึงเวลาที่แน่นอนอีกต่อไป นี่คือเหตุผลที่คุณไม่ต้องการจัดเก็บการประทับเวลาtimestampและโดยปกติแล้วจะใช้งานtimestamptz- ภาพยนตร์อาจได้รับการเผยแพร่ในเวลา 18.00 น. ตามวันที่กำหนดในทุกเขตเวลานั่นเป็นกรณีการใช้งาน

หากคุณเท่านั้นที่เคยทำงานในเขตเวลาเดียวที่คุณอาจได้รับไปด้วย timestamp(MIS) การแปลงกลับtimestamptzเป็นฉลาดพอที่จะรับมือกับ DST และจะใช้การประทับเวลาเพื่อจุดประสงค์ในการแปลงให้อยู่ในเขตเวลาปัจจุบัน นี่คือตัวอย่างสำหรับ 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

แต่ให้สังเกตพฤติกรรมที่ทำให้สับสนดังนี้

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

นี่เป็นเพราะ :

PostgreSQL ไม่เคยตรวจสอบเนื้อหาของสตริงตัวอักษรก่อนที่จะกำหนดประเภทของมันและดังนั้นจะถือว่าทั้ง [... ] เป็นเวลาที่ไม่มีเขตเวลา เพื่อให้แน่ใจว่าตัวอักษรได้รับการปฏิบัติเสมือนเป็นการประทับเวลาที่มีเขตเวลาให้เป็นประเภทที่ชัดเจนที่ถูกต้อง ... ในตัวอักษรที่ได้รับการพิจารณาให้เป็นการประทับเวลาโดยไม่มีเขตเวลา PostgreSQL จะไม่สนใจตัวบ่งชี้เขตเวลาใด ๆ


ความคิดใด ๆ วิธีการแปลงทศนิยมผลลัพธ์เป็นจำนวนเต็มโดยไม่ต้องจุดทศนิยม (ฉันหมายถึงการรวมตัวเลขและทศนิยมเป็นจำนวนเต็มขนาดใหญ่หนึ่ง) ขอบคุณ
WM

เช่นนี้แต่ฉันแน่ใจว่าคุณไม่ต้องการทำเช่นนั้น บางทีคุณอาจต้องการคูณด้วยกำลังสิบและตัดทศนิยมที่เหลืออยู่?
Jack Douglas

2
@WM อาจจะเป็นแบบนี้? SELECT FLOOR(EXTRACT(epoch FROM NOW())*1000);
Joe23

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

ไม่ส่งคืนการประทับเวลาที่ถูกต้องเนื่องจากการแปลงเขตเวลา postgres จะโยนข้อมูลเขตเวลาออกจากผลลัพธ์:

9.9.3 โซนเวลา

ไวยากรณ์: การประทับเวลาที่ไม่มีเขตเวลา AT TIME ZONE zone
คืนค่า: การประทับเวลาพร้อมเขตเวลา
รักษาเวลาประทับที่กำหนดโดยไม่มีเขตเวลาตามที่อยู่ในเขตเวลาที่ระบุ

ไวยากรณ์: การประทับเวลาพร้อมเขตเวลา AT TIME ZONE zone
คืนค่า: การประทับเวลาที่ไม่มีเขตเวลา
แปลงการประทับเวลาที่กำหนดด้วยเขตเวลาเป็นเขตเวลาใหม่โดยไม่มีการกำหนดเขตเวลา

หลังจากนั้นแยกดูที่การประทับเวลาโดยไม่มีเขตเวลาและคิดว่ามันเป็นเวลาท้องถิ่น (แม้ว่ามันจะเป็นจริงแล้ว)

วิธีที่ถูกต้องจะเป็น:

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)

ในบรรทัดสุดท้ายตัวแรกat time zoneทำการแปลงตัวที่สองกำหนดเขตเวลาใหม่ให้กับผลลัพธ์

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.