SQLAlchemy DateTime часовой пояс - PullRequest
       14

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

38 голосов
/ 06 января 2009

Тип DateTime в SQLAlchemy позволяет аргументу timezone=True сохранить ненативный объект даты и времени в базу данных и вернуть его как таковой. Есть ли способ изменить часовой пояс 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: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) # это мое смещение по местному времени !!

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

...

Правда # это время даже не сохраняло часовой пояс в БД

Ответы [ 2 ]

18 голосов
/ 20 января 2009

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

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

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

7 голосов
/ 02 октября 2012

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

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

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

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...