2009-01-05 24 views
35

El tipo DateTime de SQLAlchemy permite un argumento timezone=True para guardar un objeto datetime no ingenuo en la base de datos y devolverlo como tal. ¿Hay alguna manera de modificar la zona horaria del tzinfo que SQLAlchemy transfiere, por lo que podría ser, por ejemplo, UTC? Me doy cuenta de que podría usar default=datetime.datetime.utcnow; sin embargo, este es un tiempo ingenuo que aceptaría felizmente a alguien que pasa en un tiempo de calendario basado en tiempo local ingenuo, incluso si usé timezone=True con él, porque hace que la hora local o UTC no sea ingenua sin tener una zona horaria base para normalizarla. He intentado (usando pytz) hacer que el objeto datetime no sea ingenuo, pero cuando lo guardo en el DB vuelve a ser ingenuo.SQLAlchemy DateTime timezone

Nota cómo datetime.datetime.utcnow no funciona tan bien con timezone=True:

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) # que está compensado mi hora local !!

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

datetime.timedelta (-1, 64800)

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

datetime.timedelta (0) #utc

Incluso si lo cambio para usar explícitamente UTC:

...

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) # que no hizo uso de la zona horaria que añade explícitamente

O si se me cae la 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 

...

verdadera # ni siquiera guardar una zona horaria a la db este tiempo

Respuesta

17

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

Todas las fechas y horas de zona horaria consciente se almacenan internamente en UTC. Se convierten a la hora local en la zona especificada por el parámetro de configuración de la zona horaria antes de mostrarse al cliente.

La única manera de almacenarlo con postgresql es almacenarlo por separado.

+0

es el "parámetro de configuración de la zona horaria" la información de la zona horaria en el datetime_with_timzone en la base de datos almacenada? –

+1

@Ciastopiekarz No. El parámetro de configuración 'timezone' es un parámetro de conexión del cliente. El 'datetime with time zone', cuyo valor se almacena en UTC, se convierte a la zona horaria especificada en este parámetro' timezone' antes de mostrarlo o devolverlo. Use 'SHOW timezone' para verificar qué valor tiene para su conexión actual. Piense en lo que realmente necesita: ¿necesita almacenar la hora cuando ocurrió un evento, o también necesita almacenar información en qué zona horaria se originó realmente el valor de fecha y hora almacenado? Si es el último, debe almacenar esta información por separado. – compostus

+0

si solo sé la hora en que ocurrió, pero en UTC, esa es probablemente la conexión actual, y luego, sin la información de la zona horaria, nunca sabré cuándo exactamente ocurrió la hora exacta del usuario. –

5

una solución se da en this question’s respuesta:

se puede eludir que mediante el almacenamiento de todos los objetos de tiempo (fecha) en su base de datos en UTC, y la conversión de los objetos de fecha y hora ingenuos resultantes para los conscientes de recuperación.

el único inconveniente es que se pierde la información de la zona horaria, pero probablemente sea una buena idea almacenar los objetos datetime en utc, de todos modos.

si se preocupan por la información de zona horaria, que me gustaría almacenar por separado, y sólo convertir el UTC a la hora local en el último ejemplo, es posible (por ejemplo, justo antes de mostrar)

o tal vez no es necesario cuidado después de todo, y puede usar la información de zona horaria local desde la máquina en la que ejecuta su programa, o el navegador del usuario si es una aplicación web.

+0

si de cualquier manera desaprovechamos la información de la zona horaria pero aún podemos guardar la fecha/hora en UTC, ¿por qué no guardar la fecha y la hora en una columna definida del tipo 'cadena' en lugar de' timestamptz'? –