Подтвердить что ты не робот

SQLAlchemy DateTime часовой пояс

Тип SQLAlchemy DateTime позволяет аргументу timezone=True сохранять в базе данных объект, не являющийся наивным datetime, и возвращать его как таковой. Есть ли способ изменить часовой пояс tzinfo, который передает SQLAlchemy, так что это может быть, например, UTC? Я понимаю, что могу просто использовать default=datetime.datetime.utcnow; тем не менее, это наивное время, которое с радостью согласится с тем, что кто-то перешел в наивную локальную дату и время, даже если я использовал timezone=True с ним, потому что это делает время локального или UTC не наивным без базового часового пояса, чтобы нормализовать его с помощью, Я попытался (используя pytz), чтобы сделать объект datetime не наивным, но когда я сохраняю его в БД, он возвращается наивным.

Обратите внимание, как datetime.datetime.utcnow не работает с 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, 891887))

row[1].utcoffset()

datetime.timedelta(-1, 64800) #, что мое местное смещение!

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

datetime.timedelta(-1, 64800)

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

datetime.timedelta(0) #UTC

Даже если я изменил его, чтобы явно использовать 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) # он не использовал часовой пояс, который я явно добавил

Или, если я опустил 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 # он даже не сохранил часовой пояс для db на этот раз

4b9b3361

Ответ 1

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

Все даты и время, относящиеся к времени, хранятся внутри UTC. Они будут преобразованы в локальное время в зоне, заданной параметром конфигурации часового пояса, перед тем, как отобразить его клиенту.

Единственный способ сохранить его с помощью postgresql - хранить его отдельно.

Ответ 2

решение дано в этом вопросе:

вы можете обойти это, сохранив все объекты времени (даты) в своей базе данных в UTC и преобразовывая полученные наивные объекты datetime в известные из них при поиске.

Единственным недостатком является то, что вы теряете информацию о часовом поясе, но, вероятно, хорошая идея хранить ваши объекты datetime в utc. В любом случае.

если вам нужна информация о часовом поясе, id хранит его отдельно и только преобразовывает utc в локальное время в последнем возможном экземпляре (например, прямо перед отображением)

или, может быть, вам не нужно заботиться, и может использовать локальную информацию о часовом поясе от машины, на которой запущена ваша прогама, или браузера пользователей, если это веб-приложение.