Jawaban:
Perbedaannya tercakup pada dokumentasi PostgreSQL untuk tipe tanggal / waktu . Ya, perawatan TIME
atau TIMESTAMP
berbeda antara satu WITH TIME ZONE
atau WITHOUT TIME ZONE
. Itu tidak mempengaruhi bagaimana nilai-nilai disimpan; itu mempengaruhi bagaimana mereka ditafsirkan.
Efek zona waktu pada tipe data ini dicakup secara khusus dalam dokumen. Perbedaan muncul dari apa yang dapat diketahui oleh sistem tentang nilai:
Dengan zona waktu sebagai bagian dari nilai, nilai dapat diberikan sebagai waktu lokal di klien.
Tanpa zona waktu sebagai bagian dari nilai, zona waktu default yang jelas adalah UTC, sehingga diberikan untuk zona waktu itu.
Perilaku berbeda tergantung pada setidaknya tiga faktor:
WITH TIME ZONE
atau WITHOUT TIME ZONE
) dari nilai.Berikut adalah contoh yang mencakup kombinasi faktor-faktor tersebut:
foo=> SET TIMEZONE TO 'Japan';
SET
foo=> SELECT '2011-01-01 00:00:00'::TIMESTAMP;
timestamp
---------------------
2011-01-01 00:00:00
(1 row)
foo=> SELECT '2011-01-01 00:00:00'::TIMESTAMP WITH TIME ZONE;
timestamptz
------------------------
2011-01-01 00:00:00+09
(1 row)
foo=> SELECT '2011-01-01 00:00:00+03'::TIMESTAMP;
timestamp
---------------------
2011-01-01 00:00:00
(1 row)
foo=> SELECT '2011-01-01 00:00:00+03'::TIMESTAMP WITH TIME ZONE;
timestamptz
------------------------
2011-01-01 06:00:00+09
(1 row)
foo=> SET TIMEZONE TO 'Australia/Melbourne';
SET
foo=> SELECT '2011-01-01 00:00:00'::TIMESTAMP;
timestamp
---------------------
2011-01-01 00:00:00
(1 row)
foo=> SELECT '2011-01-01 00:00:00'::TIMESTAMP WITH TIME ZONE;
timestamptz
------------------------
2011-01-01 00:00:00+11
(1 row)
foo=> SELECT '2011-01-01 00:00:00+03'::TIMESTAMP;
timestamp
---------------------
2011-01-01 00:00:00
(1 row)
foo=> SELECT '2011-01-01 00:00:00+03'::TIMESTAMP WITH TIME ZONE;
timestamptz
------------------------
2011-01-01 08:00:00+11
(1 row)
timestamp with time zone
dan timestamp without time zone
, di Postgres * tidak benar - benar menyimpan informasi zona waktu. Anda dapat mengkonfirmasi ini dengan melihat sekilas pada halaman dokumen tipe data: Kedua jenis ini menggunakan jumlah oktet yang sama dan memiliki rentang nilai penyimpanan, sehingga tidak ada ruang untuk menyimpan info zona waktu. Teks halaman mengkonfirmasi ini. Sesuatu yang keliru: "tanpa tz" berarti "abaikan offset saat memasukkan data" dan "dengan tz" berarti "gunakan offset untuk menyesuaikan ke UTC".
Saya mencoba menjelaskannya lebih dimengerti daripada dokumentasi PostgreSQL yang dimaksud.
Baik TIMESTAMP
varian menyimpan zona waktu (atau offset), meskipun apa nama menyarankan. Perbedaannya terletak pada interpretasi data yang disimpan (dan dalam aplikasi yang dimaksud), bukan dalam format penyimpanan itu sendiri:
TIMESTAMP WITHOUT TIME ZONE
menyimpan waktu tanggal lokal (alias. tanggal kalender dinding dan waktu jam dinding). Zona waktunya tidak ditentukan sejauh yang PostgreSQL tahu (meskipun aplikasi Anda mungkin tahu apa itu). Karenanya, PostgreSQL tidak melakukan konversi terkait zona waktu pada input atau output. Jika nilai dimasukkan ke dalam basis data sebagai '2011-07-01 06:30:30'
, maka tidak ada mater di zona waktu yang Anda tampilkan nanti, itu masih akan mengatakan tahun 2011, bulan 07, hari 01, 06 jam, 30 menit, dan 30 detik (dalam beberapa format). Juga, setiap offset atau zona waktu yang Anda tentukan dalam input diabaikan oleh PostgreSQL, jadi '2011-07-01 06:30:30+00'
dan '2011-07-01 06:30:30+05'
sama dengan adil '2011-07-01 06:30:30'
. Untuk pengembang Java: analog dengan java.time.LocalDateTime
.
TIMESTAMP WITH TIME ZONE
menyimpan titik pada garis waktu UTC. Kelihatannya (berapa jam, menit, dll.) Tergantung pada zona waktu Anda, tetapi selalu mengacu pada instan "fisik" yang sama (seperti saat peristiwa fisik aktual). Input secara internal dikonversi ke UTC, dan begitulah disimpan. Untuk itu, offset input harus diketahui, jadi ketika input tersebut tidak mengandung offset atau zona waktu eksplisit (seperti '2011-07-01 06:30:30'
) itu dianggap berada di zona waktu saat ini dari sesi PostgreSQL, jika tidak, zona offset atau zona waktu yang ditentukan secara eksplisit digunakan (seperti dalam '2011-07-01 06:30:30+05'
). Outputnya ditampilkan dikonversi ke zona waktu saat ini dari sesi PostgreSQL. Untuk pengembang Java: Ini analog dengan java.time.Instant
(dengan resolusi lebih rendah), tetapi dengan JDBC dan JPA 2.2 Anda seharusnya memetakannya ke java.time.OffsetDateTime
(atau ke java.util.Date
ataujava.sql.Timestamp
tentu saja).
Ada yang mengatakan bahwa kedua TIMESTAMP
variasi menyimpan waktu tanggal UTC. Agak, tapi itu membingungkan menurut saya. TIMESTAMP WITHOUT TIME ZONE
disimpan seperti TIMESTAMP WITH TIME ZONE
, yang diberikan dengan zona waktu UTC terjadi untuk memberikan tahun yang sama, bulan, hari, jam, menit, detik, dan mikrodetik seperti yang ada di waktu-tanggal lokal. Tapi itu tidak dimaksudkan untuk mewakili titik pada garis waktu yang menurut interpretasi UTC, itu hanya cara bidang tanggal waktu setempat dikodekan. (Ini adalah beberapa titik pada garis waktu, karena zona waktu sebenarnya bukan UTC; kami tidak tahu apa itu.)
TIMESTAMP WITH TIME ZONE
a Instant
. Keduanya mewakili titik pada timeline di UTC. Instant
lebih disukai, menurut saya, lebih OffsetDateTime
karena lebih mendokumentasikan diri sendiri: A TIMESTAMP WITH TIME ZONE
selalu diambil dari database sebagai UTC, dan Instant
selalu dalam UTC sehingga cocok secara alami, sementara yang OffsetDateTime
dapat membawa offset lainnya.
OffsetDateTime
sebagai tipe Java yang dipetakan. Saya tidak yakin apakah Instance
masih didukung di suatu tempat secara tidak resmi.
'2011-07-01 06:30:30+00'
dan '2011-07-01 06:30:30+05'
diabaikan tapi saya bisa lakukan insert into test_table (date) values ('2018-03-24T00:00:00-05:00'::timestamptz);
dan itu akan mengubahnya menjadi utc dengan benar. di mana tanggal adalah timestamp tanpa zona waktu. Saya mencoba memahami apa nilai utama cap waktu dengan zona waktu dan mengalami masalah.
::timestamptz
. Dengan itu Anda mengonversi string menjadi TIMESTAMP WITH TIME ZONE
, dan saat itu akan dikonversi lebih jauh WITHOUT TIME ZONE
, yang akan menyimpan hari "kalender dinding" dan waktu jam dinding instan itu seperti yang terlihat dari zona waktu sesi Anda (yang mungkin UTC). Masih hanya akan menjadi timestamp lokal dengan offset yang tidak ditentukan (tanpa zona).
Berikut adalah contoh yang dapat membantu. Jika Anda memiliki stempel waktu dengan zona waktu, Anda dapat mengubah stempel waktu itu menjadi zona waktu lainnya. Jika Anda belum memiliki zona waktu basis, zona waktu itu tidak akan dikonversi dengan benar.
SELECT now(),
now()::timestamp,
now() AT TIME ZONE 'CST',
now()::timestamp AT TIME ZONE 'CST'
Keluaran:
-[ RECORD 1 ]---------------------------
now | 2018-09-15 17:01:36.399357+03
now | 2018-09-15 17:01:36.399357
timezone | 2018-09-15 08:01:36.399357
timezone | 2018-09-16 02:01:36.399357+03
timestamp
dan timestamptz
artinya. timestamptz
berarti titik absolut dalam waktu (UTC) sedangkan timestamp
menunjukkan apa yang ditunjukkan jam di zona waktu tertentu. Jadi, ketika mengkonversi timestamptz
ke zona waktu Anda bertanya apa yang ditunjukkan jam di New York pada titik waktu absolut ini? sedangkan ketika "mengubah" a timestamp
, Anda bertanya apa titik absolut waktu ketika jam di New York menunjukkan x?
AT TIME ZONE
membangun adalah otak teaser sendiri, bahkan jika Anda sudah memahami WITH
vs WITHOUT TIME ZONE
jenis. Jadi itu pilihan yang aneh untuk menjelaskannya. (: ( AT TIME ZONE
mengubah WITH TIME ZONE
cap waktu menjadi WITHOUT TIME ZONE
cap waktu, dan sebaliknya ... tidak terlalu jelas.)
now()::timestamp AT TIME ZONE 'CST'
tidak masuk akal, kecuali Anda apa pada jam berapa CST 'zona waktu akan menunjukkan waktu bahwa jam lokal Anda saat ini menunjukkan