python - query - sqlalchemy documentation
SQLAlchemy DateTime zona horaria (2)
El tipo DateTime
de SQLAlchemy permite una timezone=True
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 de tzinfo
que SQLAlchemy tzinfo
para que pueda ser, por ejemplo, UTC? Me doy cuenta de que solo podría usar default=datetime.datetime.utcnow
; sin embargo, este es un tiempo ingenuo que aceptaría felizmente a alguien que pasa en una fecha de inicio basada en tiempo local ingenua, incluso si utilicé la 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 como ingenuo.
Observe cómo datetime.datetime.utcnow no funciona con timezone=True
tan bien:
import sqlalchemy as sa
from sqlalchemy.sql import select
import datetime
metadata = sa.MetaData(''postgres://user:pass@machine/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, 891887))
row[1].utcoffset()
datetime.timedelta (-1, 64800) # ¡esa es mi compensación de 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 UTC explícitamente:
...
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) # no usó la zona horaria que agregué explícitamente
O si dejo caer 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
...
True # ni siquiera guardo una zona horaria para el db esta vez
http://www.postgresql.org/docs/8.3/interactive/datatype-datetime.html#DATATYPE-TIMEZONES
Todas las fechas y horas con reconocimiento de zona horaria 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 forma de almacenarlo con postgresql es almacenarlo por separado.
una solución se da en la respuesta de esta pregunta :
puede eludir eso al almacenar todos los objetos de tiempo (fecha) en su base de datos en UTC, y convertir los objetos ingenuos de fecha y hora resultantes a los conscientes en la recuperación.
el único inconveniente es que pierdes información de zona horaria, pero probablemente sea una buena idea almacenar tus objetos datetime en utc, de todos modos.
si le importa la información de la zona horaria, la almacenaría por separado, y solo convertiría el utc a la hora local en la última instancia posible (por ejemplo, justo antes de mostrar)
o tal vez no necesites preocuparte por nada, y puedes utilizar la información de la zona horaria local desde la máquina donde ejecutas tu programa, o el navegador del usuario si es una aplicación web.