Yanıtlar:
Farklılıklar, tarih / saat türleri için PostgreSQL belgelerinde ele alınmıştır . Evet, tedavisi TIME
veya TIMESTAMP
biri WITH TIME ZONE
veyaWITHOUT TIME ZONE
. Değerlerin nasıl saklandığını etkilemez; nasıl yorumlandıklarını etkiler.
Saat dilimlerinin bu veri türleri üzerindeki etkileri özellikle dokümanlarda yer almaktadır. Fark, sistemin değer hakkında makul bir şekilde bildikleri şeyden kaynaklanır:
Değerin bir parçası olarak bir saat dilimi ile, değer istemcide yerel bir saat olarak görüntülenebilir.
Değerin bir parçası olarak saat dilimi olmadan, varsayılan varsayılan saat dilimi UTC'dir, bu nedenle o saat dilimi için oluşturulur.
Davranış en az üç faktöre bağlı olarak değişir:
WITH TIME ZONE
veya WITHOUT TIME ZONE
).İşte bu faktörlerin kombinasyonlarını kapsayan örnekler:
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
ve timestamp without time zone
Postgres'te * saat dilimi bilgilerinin gerçekte saklanmadığını anlamalıdır . Bunu veri türü doc sayfasına bir bakışta doğrulayabilirsiniz: Her iki tür de aynı sayıda sekizli alır ve kaydedilen değer aralığına sahiptir, bu nedenle zaman dilimi bilgilerini depolamak için yer yoktur. Sayfanın metni bunu doğrular. Bir yanlış adlandırma: "tz olmadan", "veri eklenirken ofseti yoksay" ve "tz ile", UTC'ye ayarlamak için ofseti kullan "anlamına gelir.
Söz konusu PostgreSQL belgelerinden daha anlaşılır bir şekilde açıklamaya çalışıyorum.
Her iki TIMESTAMP
değişken de adların önerdiğine rağmen bir saat dilimi (veya bir uzaklık) depolamaz. Fark, depolama biçiminde değil, depolanan verilerin yorumlanmasında (ve amaçlanan uygulamada):
TIMESTAMP WITHOUT TIME ZONE
yerel tarih saatini saklar (duvar takvimi tarihi ve duvar saati saati olarak da bilinir). Saat dilimi PostgreSQL'in anlayabileceği kadarıyla belirtilmemiş (uygulamanız ne olduğunu biliyor olsa da). Bu nedenle, PostgreSQL giriş veya çıkışta saat dilimi ile ilgili bir dönüştürme yapmaz. Değer veritabanına olarak girildiyse '2011-07-01 06:30:30'
, daha sonra hangi saat diliminde görüntülediğiniz hiçbir materyal yoksa, yine de 2011 yılı, 07, ay 01, 06 saat, 30 dakika ve 30 saniye (bazı formatlarda) der. Ayrıca, herhangi bir ofset veya giriş belirttiğiniz saat dilimi PostgreSQL tarafından göz ardı edilir, böylece '2011-07-01 06:30:30+00'
ve '2011-07-01 06:30:30+05'
sadece aynıdır '2011-07-01 06:30:30'
. Java geliştiricileri için: buna benzer java.time.LocalDateTime
.
TIMESTAMP WITH TIME ZONE
UTC zaman çizgisinde bir nokta saklar. Görünüşü (kaç saat, dakika vb.) Saat diliminize bağlıdır, ancak her zaman aynı "fiziksel" anı ifade eder (gerçek bir fiziksel olayın anı gibi). Giriş dahili olarak UTC'ye dönüştürülür ve bu şekilde kaydedilir. Bunun için, girdinin ofseti bilinmelidir, bu nedenle girdi hiçbir kesin ofset veya zaman dilimi (zaman) içermediğinde '2011-07-01 06:30:30'
, PostgreSQL oturumunun geçerli saat diliminde olduğu varsayılır, aksi takdirde açıkça belirtilen ofset veya saat dilimi kullanılır. (olduğu gibi '2011-07-01 06:30:30+05'
). Çıktı, PostgreSQL oturumunun geçerli saat dilimine dönüştürülmüş olarak görüntülenir. Java geliştiricileri için: java.time.Instant
(ancak daha düşük çözünürlükle), ancak JDBC ve JPA 2 ile benzerdir .java.time.OffsetDateTime
java.util.Date
veyajava.sql.Timestamp
Bazıları her iki TIMESTAMP
varyasyonun UTC tarih-saatini sakladığını söylüyor . Bir tür, ama bence bu şekilde koymak kafa karıştırıcı. UTC saat dilimi ile oluşturulan TIMESTAMP WITHOUT TIME ZONE
a TIMESTAMP WITH TIME ZONE
, yerel tarih saatindekilerle aynı yıl, ay, gün, saat, dakika, saniye ve mikrosaniye verir. Ancak, UTC yorumunun söylediği zaman çizgisindeki noktayı temsil etmek anlamına gelmez, sadece yerel tarih-saat alanlarının kodlanma şekli. (Gerçek zaman dilimi UTC olmadığından, zaman çizgisindeki bazı noktalar kümesi; ne olduğunu bilmiyoruz.)
TIMESTAMP WITH TIME ZONE
yanı yoktur Instant
. Her ikisi de UTC'de zaman çizelgesinde bir noktayı temsil eder. Instant
bence OffsetDateTime
, daha fazla kendi kendini belgelediği için tercih edilir : A TIMESTAMP WITH TIME ZONE
her zaman veritabanından UTC olarak alınır ve Instant
her zaman UTC'de bulunur, bu nedenle doğal bir eşleşme olurken, bir OffsetDateTime
başka ofsetleri taşıyabilir.
OffsetDateTime
eşlenen Java türü olarak bahsedilmektedir . Instance
Hala bir yerde gayri resmi olarak desteklenip desteklenmediğinden emin değilim .
'2011-07-01 06:30:30+00'
ve '2011-07-01 06:30:30+05'
yok sayılır ama yapmak mümkün insert into test_table (date) values ('2018-03-24T00:00:00-05:00'::timestamptz);
ve doğru utc dönüştürecektir. tarih saat dilimi olmadan zaman damgasıdır. Zaman damgası ile zaman damgasının ana değerinin ne olduğunu anlamaya çalışıyorum ve sorun yaşıyorum.
::timestamptz
. Bununla birlikte, dizeyi dönüştürürsünüz TIMESTAMP WITH TIME ZONE
ve daha sonra ne zaman dönüştürülürse WITHOUT TIME ZONE
, oturum saat diliminizden (belki UTC) görüldüğü gibi o anın "duvar takvimi" gününü ve duvar saati saatini depolar. Yine de yalnızca belirtilmemiş ofseti olan (bölge yok) yerel bir zaman damgası olacaktır.
İşte size yardımcı olacak bir örnek. Saat dilimine sahip bir zaman damganız varsa, bu zaman damgasını başka bir saat dilimine dönüştürebilirsiniz. Temel saat dilimine sahip değilseniz, doğru şekilde dönüştürülmez.
SELECT now(),
now()::timestamp,
now() AT TIME ZONE 'CST',
now()::timestamp AT TIME ZONE 'CST'
Çıktı:
-[ 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
ve ne timestamptz
anlama geldiğini anlamalısınız . timestamptz
saatin (UTC) mutlak bir noktası anlamına gelirken timestamp
, belirli bir saat diliminde saatin ne gösterdiğini gösterir. Böylece, timestamptz
bir saat dilimine dönüştürürken New York'ta saatin bu mutlak noktada ne gösterdiğini soruyorsunuz ? oysa a'yı dönüştürürken , New York'ta saat x'i gösterdiğinde mutlak noktanın netimestamp
olduğunu soruyorsunuz ?
AT TIME ZONE
Zaten anlamak bile yapı, kendi teaser bir beyin WITH
vs WITHOUT TIME ZONE
türlerini. Bu yüzden onları açıklamak için ilginç bir seçim. (: ( AT TIME ZONE
bir WITH TIME ZONE
zaman damgasını bir WITHOUT TIME ZONE
zaman damgasına dönüştürür ve tam tersi ... tam olarak açık değildir.)
now()::timestamp AT TIME ZONE 'CST'
'CST' bölgesi için saatin hangi saatte yerel saatinizin şu anda gösterildiğini göstermediğiniz sürece mantıklı değil