2009-01-05 5 views
35

SQLAlchemy DateTime Typ ermöglicht für ein timezone=True Argument ein nicht naives Datetime-Objekt in der Datenbank zu speichern und es als solches zurückzugeben. Gibt es eine Möglichkeit, die Zeitzone des tzinfo, die SQLAlchemy übergibt, zu ändern, so könnte es beispielsweise UTC sein? Mir ist klar, dass ich einfach default=datetime.datetime.utcnow verwenden könnte; Dies ist jedoch eine naive Zeit, die gerne jemanden akzeptieren würde, der ein naives lokales zeitbasiertes Datetime passiert, selbst wenn ich timezone=True damit verwende, weil es lokale oder UTC-Zeit nicht-naiv macht, ohne eine Basiszeitzone zu haben, um es zu normalisieren. Ich habe versucht (mit pytz), um das Datetime-Objekt nicht naiv zu machen, aber wenn ich dies in der DB speichern, kommt es als naiv zurück.SQLAlchemy DateTime Zeitzone

Hinweis, wie datetime.datetime.utcnow nicht mit timezone=True funktioniert so gut:

import sqlalchemy as sa 
from sqlalchemy.sql import select 
import datetime 

metadata = sa.MetaData('postgres://user:[email protected]/db') 

data_table = sa.Table('data', metadata, 
    sa.Column('id', sa.types.Integer, primary_key=True), 
    sa.Column('date', sa.types.DateTime(timezone=True), default=datetime.datetime.utcnow) 
) 

metadata.create_all() 

engine = metadata.bind 
conn = engine.connect() 
result = conn.execute(data_table.insert().values(id=1)) 

s = select([data_table]) 
result = conn.execute(s) 
row = result.fetchone() 

(1, datetime.datetime (2009, 1, 6, 0, 9, 36, 891.887))

row[1].utcoffset() 

datetime.timedelta (-1, 64800) #, dass meine Lokalzeit versetzt ist !!

datetime.datetime.now(tz=pytz.timezone("US/Central")) 

datetime.timedelta (-1, 64800)

datetime.datetime.now(tz=pytz.timezone("UTC")) 

datetime.timedelta (0) #UTC

Auch wenn ich es ändern um explizit UTC zu verwenden:

...

data_table = sa.Table('data', metadata, 
    sa.Column('id', sa.types.Integer, primary_key=True), 
    sa.Column('date', sa.types.DateTime(timezone=True), default=datetime.datetime.now(tz=pytz.timezone('UTC'))) 
) 

row[1].utcoffset() 

...

datetime.timedelta (-1, 64800) # es nicht die Zeitzone verwenden, habe ich hinzugefügt ausdrücklich

Oder wenn ich fallen die timezone=True:

...

data_table = sa.Table('data', metadata, 
    sa.Column('id', sa.types.Integer, primary_key=True), 
    sa.Column('date', sa.types.DateTime(), default=datetime.datetime.now(tz=pytz.timezone('UTC'))) 
) 

row[1].utcoffset() is None 

...

Wahre # es nicht einmal eine Zeitzone an die DB diesmal

Antwort

17

http://www.postgresql.org/docs/8.3/interactive/datatype-datetime.html#DATATYPE-TIMEZONES

Alle Zeitzone-aware Daten und Zeiten gespeichert haben werden gespeichert intern in UTC. Sie werden in der vom Konfigurationsparameter timezone angegebenen Zone in die lokale Zeit konvertiert, bevor sie dem Client angezeigt werden.

Die einzige Möglichkeit, es mit postgresql zu speichern, ist es separat zu speichern.

+0

ist der "timezone configuration parameter" die timezone info in der datetime_with_timzone in der gespeicherten Datenbank? –

+1

@Ciastopiekarz Nein. Der Konfigurationsparameter 'timezone' ist ein Client-Verbindungsparameter. Die "Datetime mit Zeitzone", deren Wert in UTC gespeichert wird, wird in die Zeitzone konvertiert, die in diesem Zeitzonenparameter angegeben ist, bevor sie angezeigt oder zurückgegeben wird. Verwenden Sie 'SHOW timezone' um zu prüfen, welchen Wert es für Ihre aktuelle Verbindung hat. Denken Sie darüber nach, was Sie wirklich benötigen: Müssen Sie die Zeit speichern, zu der ein Ereignis aufgetreten ist, oder müssen Sie auch Informationen speichern, in welcher Zeitzone der gespeicherte datetime-Wert tatsächlich entstanden ist? Wenn es Letzteres ist, müssen Sie diese Informationen getrennt speichern. – compostus

+0

wenn ich nur die Zeit kenne, als es auftrat, aber in UTC, das ist wahrscheinlich aktuelle Verbindung, dann werde ich ohne Zeitzoneninfo nie wissen, wann genau die richtige Zeit des Benutzers irgendein Ereignis stattgefunden hat. –

5

eine Lösung in this question’s Antwort gegeben:

Sie, dass durch die Speicherung aller (Datum) Zeit in UTC, und die erhaltenen naiven Datetime-Objekte bewusst diejenigen auf Abruf Objekte in Ihrer Datenbank umgehen können.

Der einzige Nachteil ist, dass Sie Zeitzone Informationen verlieren, aber es ist wahrscheinlich eine gute Idee, Ihre Datetime-Objekte in Utc sowieso zu speichern.

, wenn Sie über die Zeitzoneninformationen kümmern, würde ich es separat speichern und nur die utc in der lokalen Zeit in der allerletzten Instanz konvertieren (zB direkt vor der Anzeige)

oder vielleicht brauchen Sie nicht zu Vorsicht und schließlich können Sie lokale Zeitzoneninformationen von dem Computer, auf dem Sie Ihr Programm ausführen, oder vom Browser des Benutzers verwenden, wenn es sich um eine Webanwendung handelt.

+0

Wenn wir entweder die Zeitzoneninformation verlieren, aber trotzdem das Datum/die Zeit in UTC speichern können, dann speichern wir die Datumszeit mit der Zeitzone in eine Spalte, die vom Typ 'string' anstatt von' timestamptz' definiert ist. –