Menggunakan waktu saat ini di UTC sebagai nilai default di PostgreSQL

172

Saya memiliki kolom TIMESTAMP WITHOUT TIME ZONEjenis dan ingin memiliki default ke waktu saat ini di UTC. Mendapatkan waktu saat ini di UTC mudah:

postgres=# select now() at time zone 'utc';
          timezone          
----------------------------
 2013-05-17 12:52:51.337466
(1 row)

Seperti menggunakan cap waktu saat ini untuk sebuah kolom:

postgres=# create temporary table test(id int, ts timestamp without time zone default current_timestamp);
CREATE TABLE
postgres=# insert into test values (1) returning ts;
             ts             
----------------------------
 2013-05-17 14:54:33.072725
(1 row)

Tapi itu menggunakan waktu setempat. Mencoba memaksakan hal itu kepada UTC menghasilkan kesalahan sintaksis:

postgres=# create temporary table test(id int, ts timestamp without time zone default now() at time zone 'utc');
ERROR:  syntax error at or near "at"
LINE 1: ...int, ts timestamp without time zone default now() at time zo...
Wichert Akkerman
sumber

Jawaban:

297

Fungsi bahkan tidak diperlukan. Letakkan tanda kurung di sekitar ekspresi default:

create temporary table test(
    id int, 
    ts timestamp without time zone default (now() at time zone 'utc')
);
Daniel Vérité
sumber
2
Saya dapat melihat funciton seperti now_utc () benar-benar bersinar ketika menulis kueri
misaxi
Ini bahkan bekerja ketika waktu kembali satu jam - sekarang () mengembalikan timestamp yang mengetahui offset dari UTC.
Clay Lenhart
1
FWIW, menjalankan query ini di PostgreSQL 11,5: ALTER TABLE testcase_result ADD COLUMN date_created TIMESTAMP WITHOUT TIME ZONE DEFAULT (NOW() AT TIME ZONE "UTC") NOT NULL;gagal dengan: ERROR: column "UTC" does not exist. Pastikan 'utc'semua huruf kecil.
code_dredd
2
Koreksi: 'utc'String juga harus memiliki tanda kutip tunggal, bukan tanda kutip ganda.
code_dredd
56

Masih solusi lain:

timezone('utc', now())
martti
sumber
26

Bungkus dalam suatu fungsi:

create function now_utc() returns timestamp as $$
  select now() at time zone 'utc';
$$ language sql;

create temporary table test(
  id int,
  ts timestamp without time zone default now_utc()
);
Denis de Bernardy
sumber
16

Bagaimana dengan

now()::timestamp

Jika cap waktu Anda yang lain tanpa zona waktu maka pemeran ini akan menghasilkan jenis pencocokan "cap waktu tanpa zona waktu" untuk waktu saat ini.

Saya ingin membaca pendapat orang lain tentang opsi itu. Saya masih tidak percaya pada pemahaman saya tentang hal-hal "dengan / tanpa" zona waktu ini.

EDIT: Menambahkan komentar Michael Ekoka di sini karena itu mengklarifikasi poin penting:

Peringatan. Pertanyaannya adalah tentang membuat stempel waktu default di UTC untuk kolom stempel waktu yang kebetulan tidak menyimpan zona waktu (mungkin karena tidak perlu menyimpan zona waktu jika Anda tahu bahwa semua stempel waktu Anda memiliki hal yang sama). Apa solusi Anda lakukan adalah untuk menghasilkan cap waktu lokal (yang bagi kebanyakan orang belum tentu diatur ke UTC) dan menyimpannya sebagai cap waktu naif (yang tidak menentukan zona waktu).

Risadinha
sumber
Ini adalah trik yang menarik tetapi dapat menimbulkan kebingungan kecuali Anda mengetahui perilaku ini. Jawaban yang diterima sangat jelas pada tindakan dan hasil yang diinginkan. Sama dengan fungsi tetapi saya tinggal jauh dari fungsi dalam DB ....
Frank V
dalam pilihan saya ini menghasilkan datetime lokal ke db
VelikiiNehochuha
Peringatan. Pertanyaannya adalah tentang membuat stempel waktu default di UTC untuk kolom stempel waktu yang kebetulan tidak menyimpan zona waktu (mungkin karena tidak perlu menyimpan zona waktu jika Anda tahu bahwa semua stempel waktu Anda memiliki hal yang sama). Apa solusi Anda lakukan adalah untuk menghasilkan cap waktu lokal (yang bagi kebanyakan orang belum tentu diatur ke UTC) dan menyimpannya sebagai cap waktu naif (yang tidak menentukan zona waktu).
Michael Ekoka
@MichaelEkoka Saya telah menambahkan komentar Anda ke dalam jawabannya - silakan lanjutkan dan edit jika Anda mau. Anda menjelaskannya dengan sangat jelas. Terima kasih!
Risadinha
Peringatan : cap waktu dengan bidang zona waktu TIDAK menyimpan zona waktu, bertentangan dengan asumsi yang masuk akal. Lihat tautan di bawah dan cari halaman untuk UTC. Pada input, cap waktu dengan zona waktu mengkonversi nilai yang masuk ke utc dan menyimpan nilai itu TANPA WAKTU ZONA WAKTU ATAU INFORMASI OFFSET . Pada output, nilai utc yang disimpan dikonversi ke waktu lokal menggunakan zona waktu klien jika tersedia. Jenis ini adalah tentang konversi nilai pada waktu kueri. Anda harus menguji ini dengan menyimpan dari satu zona waktu dan memilih dari zona yang berbeda. postgresql.org/docs/11/datatype-datetime.html
Tom
7

Ini adalah 2 solusi yang setara:

(dalam kode berikut, Anda harus mengganti 'UTC'untuk zona dan now()untuk timestamp )

  1. timestamp AT TIME ZONE zone - SQL-standar-sesuai
  2. timezone(zone, timestamp) - bisa dibilang lebih mudah dibaca

Fungsi zona waktu (zona, timestamp) setara dengan timestamp konstruk yang sesuai dengan SQL AT zona ZONA WAKTU.


Penjelasan:

  • zona dapat ditentukan sebagai string teks (misalnya, 'UTC') atau sebagai interval (misalnya, INTERVAL '-08:00') - di sini adalah daftar semua zona waktu yang tersedia
  • timestamp dapat berupa nilai dari timestamp apa pun
  • now()mengembalikan nilai jenis cap waktu (hanya yang kami butuhkan) dengan zona waktu default database Anda terlampir (mis 2018-11-11T12:07:22.3+05:00.).
  • timezone('UTC', now())Ternyata waktu saat kami (tipe timestamp dengan zona waktu ) menjadi setara timezonless di UTC.
    Misalnya, SELECT timestamp with time zone '2020-03-16 15:00:00-05' AT TIME ZONE 'UTC'akan kembali 2020-03-16T20:00:00Z.

Documents: zona waktu ()

danau
sumber
1
Terima kasih telah meringkas hal-hal ini. Saya menggunakan versi huruf kecil at timezone 'utc'dan itu tidak berfungsi dengan pengaturan PostgreSQL saya. Menggunakan huruf besar memecahkan masalah
Geradlus_RU
2

Fungsi sudah ada: zona waktu ('UTC' :: teks, sekarang ())

pengguna10259440
sumber