SQLAlchemy DateTime zona horaria
-
03-07-2019 - |
Pregunta
DateTime
de SQLAlchemy permite un argumentotimezone = True
para guardar un objeto datetime no ingenuo en la base de datos y devolverlo como tal. ¿Hay alguna forma de modificar la zona horaria deltzinfo
que SQLAlchemy pasa por lo que podría ser, por ejemplo, UTC? Me doy cuenta de que solo podría usardefault = datetime.datetime.utcnow
; sin embargo, este es un momento ingenuo que aceptaría felizmente a alguien que pasara en una fecha de datación basada en el tiempo local ingenuo, incluso si usaratimezone = True
, porque hace que la hora local o UTC no sea ingenua sin tener Una zona horaria base para normalizarlo con. He intentado (usando pytz ) hacer que el objeto datetime no sea ingenuo, pero cuando guardo esto en el DB vuelve como ingenuo.Observe que 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) # ¡ese es mi desplazamiento 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 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) # no usó la zona horaria que agregué explícitamente
O si suelto el
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 guardó una zona horaria en la base de datos esta vez
Solución
http://www.postgresql.org/ docs / 8.3 / interactive / datatype-datetime.html # DATATYPE-TIMEZONES
Todas las fechas y horas basadas en la 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.
Otros consejos
se proporciona una solución en esta pregunta responde:
puede evitarlo almacenando todos los objetos de la hora (fecha) en su base de datos en UTC y convirtiendo los objetos de fecha y hora ingenuos resultantes en objetos conscientes en la recuperación.
el único inconveniente es que pierdes la información de la zona horaria, pero de todos modos, probablemente sea una buena idea almacenar tus objetos de fecha y hora en utc.
si te 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 quizás no deba preocuparse después de todo, y puede usar la información de la zona horaria local de la máquina en la que ejecuta su programa, o el navegador del usuario si se trata de una aplicación web.