it-swarm.asia

Bagaimana cara mendapatkan cap waktu unix saat ini dari PostgreSQL?

nix timestamp adalah jumlah detik sejak tengah malam UTC 1 Januari 1970.

Bagaimana cara mendapatkan cap waktu unix yang benar dari PostgreSQL?

Ketika membandingkan ke currenttimestamp.com dan timestamp.1e5b.de Saya tidak mendapatkan waktu yang diharapkan dari PostgreSQL:

Ini mengembalikan stempel waktu yang benar:

SELECT extract(Epoch from now());

Meskipun ini tidak:

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

Saya tinggal di zona waktu UTC +02. Apa cara yang benar untuk mendapatkan cap waktu unix saat ini dari PostgreSQL?

Ini mengembalikan waktu dan zona waktu yang benar:

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

Perbandingan lain:

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
99
Jonas

Dalam postgres, timestamp with time zone Dapat disingkat sebagai timestamptz, dan timestamp without time zone Sebagai timestamp. Saya akan menggunakan nama jenis yang lebih pendek untuk kesederhanaan.

Mendapatkan cap waktu Unix dari postgres timestamptz like now() sederhana, seperti yang Anda katakan, cukup:

select extract(Epoch from now());

Itu benar-benar semua yang perlu Anda ketahui tentang mendapatkan waktu absolut dari apa pun yang bertipe timestamptz, termasuk now().

Hal-hal hanya menjadi rumit ketika Anda memiliki bidang timestamp.

Ketika Anda memasukkan timestamptz data seperti now() ke dalam bidang itu, pertama-tama ia akan dikonversi ke zona waktu tertentu (baik secara eksplisit dengan at time zone Atau dengan mengonversi ke zona waktu sesi) dan informasi zona waktu dibuang . Itu tidak lagi mengacu pada waktu absolut. Inilah sebabnya mengapa Anda biasanya tidak ingin menyimpan cap waktu sebagai timestamp dan biasanya menggunakan timestamptz - mungkin sebuah film dirilis pada pukul 6 sore pada tanggal tertentu di setiap zona waktu , itulah jenis kasus penggunaan.

Jika Anda hanya pernah bekerja di zona waktu tunggal, Anda mungkin lolos dengan (mis) menggunakan timestamp. Konversi kembali ke timestamptz cukup pintar untuk mengatasi DST, dan cap waktu diasumsikan, untuk tujuan konversi, berada di zona waktu saat ini. Berikut ini contoh untuk 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

Tapi, perhatikan perilaku membingungkan berikut:

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

Ini karena :

PostgreSQL tidak pernah memeriksa konten string literal sebelum menentukan jenisnya, dan karena itu akan memperlakukan keduanya […] sebagai timestamp tanpa zona waktu. Untuk memastikan bahwa literal diperlakukan sebagai timestamp dengan zona waktu, berikan tipe eksplisit yang benar ... Dalam literal yang telah ditentukan sebagai timestamp tanpa zona waktu, PostgreSQL diam-diam akan mengabaikan indikasi zona waktu apa pun

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

tidak mengembalikan stempel waktu yang benar karena konversi zona waktu postgres membuang informasi zona waktu dari hasilnya:

9.9.3. AT ZONA WAKTU

Sintaks: timestamp tanpa zona waktu AT Zona ZONA WAKTU
Pengembalian: cap waktu dengan zona waktu
Perlakukan stempel waktu yang diberikan tanpa zona waktu seperti yang terletak di zona waktu yang ditentukan

Sintaks: timestamp dengan zona waktu AT zona ZONA WAKTU
Pengembalian: timestamp tanpa zona waktu
Konversi stempel waktu yang diberikan dengan zona waktu ke zona waktu baru, tanpa penunjukan zona waktu

setelah itu, ekstrak melihat stempel waktu tanpa zona waktu dan menganggapnya sebagai waktu lokal (meskipun sebenarnya sudah utc).

Cara yang benar adalah:

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)

Di baris terakhir yang pertama at time zone Melakukan konversi, yang kedua memberikan zona waktu baru ke hasilnya.

23
axil