Differenza tra timestamp con / senza fuso orario in PostgreSQL


Risposte:


157

Le differenze sono trattate nella documentazione di PostgreSQL per i tipi di data / ora . Sì, il trattamento TIMEo TIMESTAMPdifferisce tra uno WITH TIME ZONEo 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:

  • L'impostazione del fuso orario nel client.
  • Il tipo di dati (ovvero WITH TIME ZONEo WITHOUT TIME ZONE) del valore.
  • Se il valore viene specificato con un determinato fuso orario.

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)

88
Corretto solo se riferito al processo di inserimento / recupero di valori. Ma i lettori dovrebbero capire che entrambi i tipi di dati timestamp with time zonee 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".
Basil Bourque,

42
I tipi di dati sono un termine improprio in un secondo modo: dicono "fuso orario" ma in realtà stiamo parlando di offset da UTC / GMT. Un fuso orario è in realtà un offset più regole / cronologia sull'ora legale (DST) e altre anomalie.
Basil Bourque,

4
Preferirei dire che un offset è un fuso orario più regole per l'ora legale. Non è possibile rilevare il fuso orario dato un offset, ma è possibile rilevare l'offset dato il fuso orario e le regole DST.
igorsantos07,

3
Citando il documento ufficiale : tutte le date e gli orari sensibili al fuso orario sono memorizzati internamente in UTC. Vengono convertiti in ora locale nella zona specificata dal parametro di configurazione TimeZone prima di essere visualizzati sul client.
Guillaume Husta,

2
@ igorsantos07 Un fuso orario è l'insieme di regole / cronologia relative alle modifiche dell'ora legale e ad altre modifiche. La tua formulazione sembra superflua. E la tua affermazione che "un offset è un fuso orario più le regole per l'ora legale" è semplicemente sbagliata: un offset è semplicemente un numero di ore, minuti e secondi - niente di più, niente di meno.
Basil Bourque,

34

Cerco di spiegarlo in modo più comprensibile della documentazione PostgreSQL citata.

Nessuna delle due TIMESTAMPvarianti 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 ZONEmemorizza 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 ZONEmemorizza 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.Dateojava.sql.Timestamp ovviamente).

Alcuni sostengono che entrambe le TIMESTAMPvarianti 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.)


Non c'è niente di sbagliato nel recupero di a TIMESTAMP WITH TIME ZONEcome a Instant. Entrambi rappresentano un punto della sequenza temporale in UTC. Instantè preferito, a mio avviso, rispetto a OffsetDateTimecome è più autocompattante: A TIMESTAMP WITH TIME ZONEviene sempre recuperato dal database come UTC e un Instantè sempre in UTC quindi una corrispondenza naturale, mentre OffsetDateTimepuò portare altri offset.
Basil Bourque,

@BasilBourque Sfortunatamente, l'attuale specifica JDBC, la specifica JPA 2.2 e anche la documentazione PostgreSQL JDBC menzionano solo OffsetDateTimeil tipo Java mappato. Non sono sicuro che Instancesia ancora supportato ufficiosamente da qualche parte.
Ddekany,

domanda, dici qualsiasi offset che specifico nell'input come '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.
pk1m

@ pk1m Compri le cose con il ::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).
Ddekany,

sto lavorando con Python e questo è ciò che viene inserito quando si inserisce un oggetto datettime con timestamp. Mi sembra che ci sia valore nell'utilizzare il timestamp con il fuso orario, ma non è necessario per gestire i fusi orari.
pk1m,

12

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

5
L'istruzione "non verrà convertita correttamente" semplicemente non è vera. Devi capire cosa timestampe cosa timestamptzsignifichi. timestamptzindica un punto assoluto nel tempo (UTC) mentre timestampindica ciò che l'orologio ha mostrato in un determinato fuso orario. Quindi, quando ti converti timestamptzin 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?
fphilipe,

Il AT TIME ZONEcostrutto è un rompicapo, anche se hai già capito i tipi WITHvs. WITHOUT TIME ZONEQuindi è una scelta curiosa per spiegarli. (: ( AT TIME ZONEconverte un WITH TIME ZONEtimestamp in un WITHOUT TIME ZONEtimestamp, e viceversa ... non esattamente ovvio.)
ddekany,

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
Jasen
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.