Il tipo di dati timestamp
è il nome breve per timestamp without time zone
.
L'altra opzione timestamptz
è l'abbreviazione di timestamp with time zone
.
timestamptz
è il tipo preferito nella famiglia data / ora, letteralmente. È stato typispreferred
impostato pg_type
, che può essere rilevante:
Memoria interna ed epoca
Internamente, i timestamp occupano 8 byte di memoria sul disco e nella RAM. È un valore intero che rappresenta il conteggio dei microsecondi dell'epoca di Postgres, 2000-01-01 00:00:00 UTC.
Postgres ha anche una conoscenza integrata del tempo UNIX comunemente usato che conta i secondi dall'epoca UNIX, 1970-01-01 00:00:00 UTC, e lo utilizza nelle funzioni to_timestamp(double precision)
o EXTRACT(EPOCH FROM timestamptz)
.
Il codice sorgente:
* I timestamp, così come i campi h / m / s degli intervalli, sono memorizzati come
* valori int64 con unità di microsecondi. (C'erano una volta
* valori doppi con unità di secondi.)
E:
/ * Equivalenti alla data giuliana del Giorno 0 nella contabilità Unix e Postgres * /
#define UNIX_EPOCH_JDATE 2440588 / * == date2j (1970, 1, 1) * /
#define POSTGRES_EPOCH_JDATE 2451545 / * == date2j (2000, 1, 1) * /
La risoluzione del microsecondo si traduce in un massimo di 6 cifre frazionarie per secondi.
timestamp
Un valore digitato come dice a Postgres che non viene fornito esplicitamente alcun fuso orario. Si presuppone il fuso orario corrente. Postgres ignora qualsiasi modificatore di fuso orario aggiunto per errore!timestamp
[without time zone]
Nessuna ora viene spostata per la visualizzazione. Con la stessa impostazione del fuso orario tutto va bene. Per un diverso fuso orario l'impostazione del significato cambia, ma valore e display rimangono invariati.
timestamptz
La gestione di timestamp with time zone
è leggermente diversa. Cito il manuale qui :
Per timestamp with time zone
, il valore memorizzato internamente è sempre in UTC (Universal Coordinated Time ...)
Enorme enfasi sulla mia. Il fuso orario stesso non viene mai memorizzato . È un modificatore di input utilizzato per calcolare il timestamp UTC corrispondente, che viene memorizzato - o e un modificatore di output utilizzato per calcolare l'ora locale da visualizzare - con l'offset del fuso orario aggiunto. Se non si aggiunge un offset per timestamptz
l'ingresso, si presume l'impostazione corrente del fuso orario della sessione. Tutti i calcoli vengono eseguiti con valori di data / ora UTC. Se è necessario (o potrebbe essere necessario) gestire più di un fuso orario, utilizzare timestamptz
.
I client come psql o pgAdmin o qualsiasi applicazione che comunica tramite libpq (come Ruby con la gemma pg) vengono presentati con il timestamp più l'offset per il fuso orario corrente o in base al fuso orario richiesto (vedi sotto). È sempre lo stesso punto nel tempo , varia solo il formato di visualizzazione. Oppure, come dice il manuale :
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.
Considera questo semplice esempio (in psql):
db = # SELECT timestamptz '2012-03-05 20:00 +03 ';
timestamptz
------------------------
05-03-2012 18:00:00 +01
Enorme enfasi sulla mia. Cos'è successo qua?
Ho scelto un offset di fuso orario arbitrario +3
per l'input letterale. Per Postgres, questo è solo uno dei molti modi per inserire il timestamp UTC 2012-03-05 17:00:00
. Il risultato della query viene visualizzato per l'impostazione del fuso orario corrente Vienna / Austria nel mio test, che ha un offset +1
durante l'inverno e +2
durante l'ora legale: 2012-03-05 18:00:00+01
perché cade nell'orario invernale.
Postgres ha già dimenticato come è stato inserito questo valore. Tutto ciò che ricorda è il valore e il tipo di dati. Proprio come con un numero decimale. numeric '003.4'
, numeric '3.40'
O numeric '+3.4'
- il tutto risultato nella esattamente lo stesso valore interno.
AT TIME ZONE
Non appena ottieni una comprensione di questa logica, puoi fare tutto quello che vuoi. Tutto ciò che manca ora è uno strumento per interpretare o rappresentare i letterali del timestamp in base a un fuso orario specifico. È qui che AT TIME ZONE
entra in gioco il costrutto. Esistono due diversi casi d'uso. timestamptz
viene convertito in timestamp
e viceversa.
Per inserire l'UTC timestamptz
2012-03-05 17:00:00+0
:
SELECT timestamp '2012-03-05 17:00:00' AT TIME ZONE 'UTC'
... che equivale a:
SELECT timestamptz '2012-03-05 17:00:00 UTC'
Per visualizzare lo stesso punto nel tempo di EST timestamp
(Eastern Standard Time):
SELECT timestamp '2012-03-05 17:00:00' AT TIME ZONE 'UTC' AT TIME ZONE 'EST'
Esatto, AT TIME ZONE 'UTC'
due volte . Il primo interpreta il timestamp
valore come (dato) timestamp UTC che restituisce il tipo timestamptz
. Il secondo converte il timestamptz
alla timestamp
nel dato fuso 'EST' - cosa un orologio nelle visualizzazioni dell'ora zona EST a questo punto unico nel tempo.
Esempi
SELECT ts AT TIME ZONE 'UTC'
FROM (
VALUES
(1, timestamptz '2012-03-05 17:00:00+0')
, (2, timestamptz '2012-03-05 18:00:00+1')
, (3, timestamptz '2012-03-05 17:00:00 UTC')
, (4, timestamp '2012-03-05 11:00:00' AT TIME ZONE '+6')
, (5, timestamp '2012-03-05 17:00:00' AT TIME ZONE 'UTC')
, (6, timestamp '2012-03-05 07:00:00' AT TIME ZONE 'US/Hawaii') -- ①
, (7, timestamptz '2012-03-05 07:00:00 US/Hawaii') -- ①
, (8, timestamp '2012-03-05 07:00:00' AT TIME ZONE 'HST') -- ①
, (9, timestamp '2012-03-05 18:00:00+1') -- ② loaded footgun!
) t(id, ts);
Restituisce 8 (o 9) righe identiche con colonne timestamptz che contengono lo stesso timestamp UTC 2012-03-05 17:00:00
. La 9a fila sembra funzionare nel mio fuso orario, ma è una trappola malvagia. Vedi sotto.
① Le righe 6 - 8 con il nome del fuso orario e l' abbreviazione del fuso orario per l'ora delle Hawaii sono soggette all'ora legale (ora legale) e potrebbero essere diverse, sebbene non attualmente. Un nome di fuso orario come 'US/Hawaii'
è a conoscenza delle regole dell'ora legale e di tutti i turni storici automaticamente, mentre un'abbreviazione come HST
è solo un codice stupido per un offset fisso. Potrebbe essere necessario aggiungere un'abbreviazione diversa per l'ora legale / solare. Il nome interpreta correttamente qualsiasi timestamp nel fuso orario specificato. Una sigla è a buon mercato, ma ha bisogno di essere quella giusta per il dato timestamp:
L'ora legale non è tra le idee più brillanti mai concepite dall'umanità.
② La riga 9, contrassegnata come una pistola caricata, funziona per me , ma solo per coincidenza. Se espressi esplicitamente un valore letterale timestamp [without time zone]
, qualsiasi offset del fuso orario viene ignorato ! Viene utilizzato solo il timestamp semplice. Il valore viene quindi forzato automaticamente timestamptz
nell'esempio per corrispondere al tipo di colonna. Per questo passaggio, timezone
si presume l' impostazione della sessione corrente, che risulta essere lo stesso fuso orario +1
nel mio caso (Europa / Vienna). Ma probabilmente non nel tuo caso, il che si tradurrà in un valore diverso. In breve: non lanciare timestamptz
letterali timestamp
o perdere l'offset del fuso orario.
Le tue domande
L'utente memorizza un'ora, diciamo il 17 marzo 2012, alle 19:00. Non voglio che vengano salvate le conversioni del fuso orario o il fuso orario.
Il fuso orario non viene mai memorizzato. Utilizzare uno dei metodi sopra indicati per inserire un timestamp UTC.
Uso solo il fuso orario specificato dagli utenti per ottenere i record "prima" o "dopo" l'ora corrente nel fuso orario locale degli utenti.
È possibile utilizzare una query per tutti i client in diversi fusi orari.
Per un tempo globale assoluto:
SELECT * FROM tbl WHERE time_col > (now() AT TIME ZONE 'UTC')::time
Per l'ora in base all'orologio locale:
SELECT * FROM tbl WHERE time_col > now()::time
Non sei ancora stanco delle informazioni di base? C'è di più nel manuale.