Risposte:
Le differenze sono trattate nella documentazione di PostgreSQL per i tipi di data / ora . Sì, il trattamento TIME
o TIMESTAMP
differisce tra uno WITH TIME ZONE
o WITHOUT TIME ZONE
. Non influisce sulla modalità di memorizzazione dei valori; influenza il modo in cui vengono interpretati.
Gli effetti dei fusi orari su questi tipi di dati sono trattati in modo specifico nei documenti. La differenza deriva da ciò che il sistema può ragionevolmente sapere sul valore:
Con un fuso orario come parte del valore, il valore può essere visualizzato come ora locale nel client.
Senza un fuso orario come parte del valore, il fuso orario predefinito ovvio è UTC, quindi viene visualizzato per quel fuso orario.
Il comportamento differisce in base ad almeno tre fattori:
WITH TIME ZONE
o WITHOUT TIME ZONE
) del valore.Ecco alcuni esempi che coprono le combinazioni di tali fattori:
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
e timestamp without time zone
, in Postgres * non memorizzano effettivamente le informazioni sul fuso orario. Puoi confermarlo con uno sguardo alla pagina doc del tipo di dati: Entrambi i tipi occupano lo stesso numero di ottetti e hanno l'intervallo di valori di salvataggio, quindi non c'è spazio per la memorizzazione delle informazioni sul fuso orario. Il testo della pagina lo conferma. Qualcosa di un termine improprio: "senza tz" significa "ignora offset durante l'inserimento dei dati" e "con tz" significa "usa offset per adattarsi a UTC".
Cerco di spiegarlo in modo più comprensibile della documentazione PostgreSQL citata.
Nessuna delle due TIMESTAMP
varianti memorizza un fuso orario (o un offset), nonostante ciò che suggeriscono i nomi. La differenza sta nell'interpretazione dei dati memorizzati (e nell'applicazione prevista), non nel formato di archiviazione stesso:
TIMESTAMP WITHOUT TIME ZONE
memorizza la data e l'ora locale (ovvero la data del calendario da parete e l'ora dell'orologio da parete). Il suo fuso orario non è specificato da quanto PostgreSQL può dire (sebbene l'applicazione possa sapere di cosa si tratta). Pertanto, PostgreSQL non esegue alcuna conversione relativa al fuso orario su input o output. Se il valore è stato inserito nel database come '2011-07-01 06:30:30'
, quindi nessun mater in quale fuso orario lo visualizzi in seguito, continuerà a dire anno 2011, mese 07, giorno 01, 06 ore, 30 minuti e 30 secondi (in un formato). Inoltre, qualsiasi scostamento o il fuso orario specificato nella ingresso viene ignorato da PostgreSQL, così '2011-07-01 06:30:30+00'
e '2011-07-01 06:30:30+05'
sono gli stessi solo '2011-07-01 06:30:30'
. Per gli sviluppatori Java: è analogo a java.time.LocalDateTime
.
TIMESTAMP WITH TIME ZONE
memorizza un punto sulla linea temporale UTC. Come appare (quante ore, minuti, ecc.) Dipende dal tuo fuso orario, ma si riferisce sempre allo stesso istante "fisico" (come il momento di un evento fisico reale). L'input viene convertito internamente in UTC, ed è così che viene memorizzato. Per questo, l'offset dell'ingresso deve essere noto, quindi quando l'ingresso non contiene offset o fuso orario espliciti (come '2011-07-01 06:30:30'
), si presume che si trovi nel fuso orario corrente della sessione PostgreSQL, altrimenti viene utilizzato l'offset o il fuso orario specificati in modo esplicito (come in '2011-07-01 06:30:30+05'
). L'output viene visualizzato convertito nel fuso orario corrente della sessione PostgreSQL. Per gli sviluppatori Java: è analogo a java.time.Instant
(con una risoluzione inferiore), ma con JDBC e JPA 2.2 dovresti mapparlo su java.time.OffsetDateTime
(o su java.util.Date
ojava.sql.Timestamp
ovviamente).
Alcuni sostengono che entrambe le TIMESTAMP
varianti memorizzano la data e l'ora UTC. Un po ', ma secondo me è confuso. TIMESTAMP WITHOUT TIME ZONE
è memorizzato come un TIMESTAMP WITH TIME ZONE
, che viene visualizzato con il fuso orario UTC sembra dare lo stesso anno, mese, giorno, ore, minuti, secondi e microsecondi come sono nella data-ora locale. Ma non ha lo scopo di rappresentare il punto sulla linea temporale che dice l'interpretazione UTC, è solo il modo in cui sono codificati i campi data-ora locali. (È un gruppo di punti sulla linea del tempo, poiché il fuso orario reale non è UTC; non sappiamo di cosa si tratti.)
TIMESTAMP WITH TIME ZONE
come a Instant
. Entrambi rappresentano un punto della sequenza temporale in UTC. Instant
è preferito, a mio avviso, rispetto a OffsetDateTime
come è più autocompattante: A TIMESTAMP WITH TIME ZONE
viene sempre recuperato dal database come UTC e un Instant
è sempre in UTC quindi una corrispondenza naturale, mentre OffsetDateTime
può portare altri offset.
OffsetDateTime
il tipo Java mappato. Non sono sicuro che Instance
sia ancora supportato ufficiosamente da qualche parte.
'2011-07-01 06:30:30+00'
ed '2011-07-01 06:30:30+05'
è ignorato ma sono in grado di farlo insert into test_table (date) values ('2018-03-24T00:00:00-05:00'::timestamptz);
e lo convertirà in utc correttamente. dove la data è data e ora senza fuso orario. Sto cercando di capire quale sia il valore principale del timestamp con il fuso orario e di avere problemi.
::timestamptz
. Con ciò si converte la stringa in TIMESTAMP WITH TIME ZONE
, e quando verrà ulteriormente convertita in WITHOUT TIME ZONE
, che memorizzerà il "calendario da parete" giorno e l'ora dell'orologio da parete di quell'istante, come si vede dal fuso orario della sessione (che è forse UTC). Sarà comunque solo un timestamp locale con offset non specificato (nessuna zona).
Ecco un esempio che dovrebbe aiutare. Se si dispone di un timestamp con un fuso orario, è possibile convertire tale timestamp in qualsiasi altro fuso orario. Se non hai un fuso orario di base, questo non verrà convertito correttamente.
SELECT now(),
now()::timestamp,
now() AT TIME ZONE 'CST',
now()::timestamp AT TIME ZONE 'CST'
Produzione:
-[ 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
e cosa timestamptz
significhi. timestamptz
indica un punto assoluto nel tempo (UTC) mentre timestamp
indica ciò che l'orologio ha mostrato in un determinato fuso orario. Quindi, quando ti converti timestamptz
in un fuso orario ti chiedi cosa ha mostrato l'orologio a New York in questo preciso momento? mentre quando "converti" a timestamp
, ti stai chiedendo qual è stato il momento assoluto in cui l'orologio di New York ha mostrato x?
AT TIME ZONE
costrutto è un rompicapo, anche se hai già capito i tipi WITH
vs. WITHOUT TIME ZONE
Quindi è una scelta curiosa per spiegarli. (: ( AT TIME ZONE
converte un WITH TIME ZONE
timestamp in un WITHOUT TIME ZONE
timestamp, e viceversa ... non esattamente ovvio.)
now()::timestamp AT TIME ZONE 'CST'
non ha senso, a meno che tu non sappia in quale istante un orologio per la zona 'CST' mostrerebbe l'ora che il tuo orologio locale sta attualmente mostrando