Jawaban:
Perbedaannya tercakup pada dokumentasi PostgreSQL untuk tipe tanggal / waktu . Ya, perawatan TIMEatau TIMESTAMPberbeda antara satu WITH TIME ZONEatau 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 ZONEatau 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 zonedan 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 TIMESTAMPvarian 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 ZONEmenyimpan 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 ZONEmenyimpan 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.Dateataujava.sql.Timestamp tentu saja).
Ada yang mengatakan bahwa kedua TIMESTAMPvariasi menyimpan waktu tanggal UTC. Agak, tapi itu membingungkan menurut saya. TIMESTAMP WITHOUT TIME ZONEdisimpan 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 ZONEa Instant. Keduanya mewakili titik pada timeline di UTC. Instantlebih disukai, menurut saya, lebih OffsetDateTimekarena lebih mendokumentasikan diri sendiri: A TIMESTAMP WITH TIME ZONEselalu diambil dari database sebagai UTC, dan Instantselalu dalam UTC sehingga cocok secara alami, sementara yang OffsetDateTimedapat membawa offset lainnya.
OffsetDateTimesebagai tipe Java yang dipetakan. Saya tidak yakin apakah Instancemasih 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
timestampdan timestamptzartinya. timestamptzberarti titik absolut dalam waktu (UTC) sedangkan timestampmenunjukkan apa yang ditunjukkan jam di zona waktu tertentu. Jadi, ketika mengkonversi timestamptzke 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 ZONEmembangun adalah otak teaser sendiri, bahkan jika Anda sudah memahami WITHvs WITHOUT TIME ZONEjenis. Jadi itu pilihan yang aneh untuk menjelaskannya. (: ( AT TIME ZONEmengubah WITH TIME ZONEcap waktu menjadi WITHOUT TIME ZONEcap 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