2013-11-28 12 views
13

Per un datetime conforme ISO8601Preserve fuso orario in PostgreSQL timestamptz tipo

2004-10-19 10:23:54+02 

E 'possibile avere quel valore, con +02 offset, riflette il valore della colonna memorizzato e conservato anche quando è selezionato?

Dalla lettura del comportamento predefinito di Postgres appropriate section of the docs è convertire in UTC a quel punto viene perso l'offset originale. Questo è certamente quello che sto vedendo.

È possibile accedere ai dati tramite un ORM che non è in grado di aggiungere alcuna conversione tz speciale, quindi è necessario archiviare semplicemente il datetime con lo scostamento originale e avere il valore riflesso quando selezionato.

Per chiunque muoia a dirmi che è lo stesso istante in tempo, la conservazione di questo valore ha un significato per questi dati.

+0

È possibile memorizzare l'offset in una colonna separata in modo da non essere alla mercé di Postgres? – tadman

+1

@tadman Ha. Cercando di farlo circolare in una colonna. Non sembra essere una cosa irragionevole da fare. – markdsievers

+0

Qual è l'origine dati? Una stringa letterale? O un'altra colonna - di che tipo? –

risposta

13

Come già capito da soli, il fuso orario non viene salvato a tutti con Postgres data/tipi di tempo, nemmeno con timestamptz. Il suo ruolo è solo un modificatore di input o un decoratore di output, rispettivamente. Viene salvato solo il valore (il punto nel tempo). Ampi dettagli in questa risposta Correlati:

Pertanto, se si desidera mantenere quella parte della stringa di input, è necessario estrarlo dalla stringa e salvarlo da soli. Vorrei utilizzare una tabella come:

CREATE TABLE tstz 
... 
, ts timestamp -- without time zone 
, tz text 
) 

tz, essendo text, può contenere un numerico scostamento nonché un fuso abbreviazione, o un fuso nome.

La difficoltà è estrarre la parte del fuso orario in base a tutte le varie regole che il parser segue e in un modo che non si romperà facilmente. Invece di preparare la tua procedura, fai in modo che il parser faccia il lavoro.Considerate questo demo:

WITH ts_literals (tstz) AS (
    VALUES ('2013-11-28 23:09:11.761166+03'::text) 
     ,('2013-11-28 23:09:11.761166 CET') 
     ,('2013-11-28 23:09:11.761166 America/New_York') 
    ) 
SELECT tstz 
     ,tstz::timestamp AS ts 
     ,right(tstz, -1 * length(tstz::timestamp::text)) AS tz 
FROM ts_literals;

SQL Fiddle.

funziona con o senza un T tra la data e l'ora. La logica chiave è qui:

right(tstz, -1 * length(tstz::timestamp::text)) AS tz 

prendere ciò che resta di una stringa timestamp dopo il taglio della lunghezza di ciò che il parser identificato come componente di data/ora. Questo si basa sul fatto l'ingresso, come lei ha affermato:

convalidati stringhe ISO8601

+2

Grazie per la risposta dettagliata. Così deludente questo non è possibile in una colonna. – markdsievers

+3

@markdsievers Se ci pensate, l'offset è un'informazione superflua. Il tempo "reale" è UTC/GMT, il numero di millisecondi dall'epoca. Se nel contesto della tua app e dei tuoi dati ti preoccupi veramente di preservare l'offset, significa che ti preoccupi dell'ora locale e questo significa che dovresti catturare e registrare il fuso orario. Es: "Pacific/Auckland". Il fuso orario è più di un offset, include regole/cronologia per Ora legale (DST) e altre anomalie. Senza la registrazione di un fuso orario, non vi è alcuna distinzione utile tra una data/ora + offset e una data-ora in UTC. –

1

I post nativi date/time datatypes non conserveranno il fuso orario di input per voi. Se è necessario interrogarlo come data e ora nel database e presentare le informazioni originali, è necessario archiviare entrambe le informazioni in qualche modo.

Stavo per suggerire che il tuo ORM potrebbe definire i metodi di gonfiaggio/sgonfiaggio personalizzati per gestire la magia, ma a quanto pare non può. Dovresti indicare quale ORM stai usando.

È possibile che ORM memorizzi/recuperi la stringa nel database e utilizzi un trigger in Postgres per convertirlo in un timestamptz archiviato in un'altra colonna utilizzata quando si eseguono query lato database. Se hai molte tabelle con questo tipo di dati, potrebbe essere un po 'ingombrante.

Se si desidera realmente i dati in una singola colonna nel database, è possibile definire uno composite type in Postgres, anche se l'ORM potrebbe non essere in grado di gestirli.

+0

Deliberatamente omesso i dettagli ORM poiché questo è l'argomento di un'altra domanda successiva. Questa domanda riguarda semplicemente la possibilità di memorizzare un TZ in una colonna di un tipo di timestamptz Postgres, come suggerisce il titolo. – markdsievers

2

sviluppatori Java possono utilizzare Joda Time combinata con Jadira UserType s' PersistentDateTimeAndZone. Esempio:

@Basic(optional = false) 
@Columns(columns = { @Column(name = "modificationtime"), 
     @Column(name = "modificationtime_zone") }) 
@Type(type = "org.jadira.usertype.dateandtime.joda.PersistentDateTimeAndZone") 
@Index(name = "payment_modificationtime_idx") 
private DateTime modificationTime = null; 

In questo esempio, le informazioni DateTime è in 2 colonne:

  1. modificationtime timestamp without time zone per memorizzare il timestamp UTC fuso
  2. modificationtime_zone varchar(255) per memorizzare il fuso orario ID come stringa (es)

Mentre Joda Time e Jadira (e Hibernate) sono specifici di Java (ed è il de facto approccio), l'approccio sopra descritto di strutturare le colonne RDBMS per memorizzare timestamp e fuso orario può essere applicato a qualsiasi linguaggio di programmazione.