关于python:SQLAlchemy DateTime时区

SQLAlchemy DateTime timezone

SQLAlchemy的DateTime类型允许使用timezone=True参数将非朴素的datetime对象保存到数据库,并照此返回。 有什么方法可以修改SQLAlchemy传入的tzinfo的时区,例如UTC? 我意识到我可以只使用default=datetime.datetime.utcnow; 但是,这是一个幼稚的时间,即使我使用了timezone=True,它也会很乐意接受某人传入基于本地化的本地时间的日期时间,因为它使本地或UTC时间成为非幼稚的,而没有使用基准时区对其进行规范化。 我尝试过(使用pytz)使datetime对象成为非天真的对象,但是当我将其保存到数据库时,它又回到了天真对象的状态。

请注意datetime.datetime.utcnow如何不能很好地与timezone=True一起使用:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
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))

1
row[1].utcoffset()

datetime.timedelta(-1, 64800) # that's my localtime offset!!

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

datetime.timedelta(-1, 64800)

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

datetime.timedelta(0) #UTC

即使我将其更改为显式使用UTC:

...

1
2
3
4
5
6
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) # it did not use the timezone I explicitly added

或者,如果我放下timezone=True

...

1
2
3
4
5
6
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 # it didn't even save a timezone to the db this time


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

All timezone-aware dates and times are stored internally in UTC. They are converted to local time in the zone specified by the timezone configuration parameter before being displayed to the client.

用postgresql存储它的唯一方法是分别存储它。


这个问题的答案给出了一个解决方案:

您可以通过将所有(日期)时间对象存储在UTC中的数据库中,然后将所得的简单日期时间对象转换为可检索的已知日期时间对象,来规避这一问题。

唯一的缺点是您会丢失时区信息,但是无论如何,最好将日期时间对象存储在utc中。

如果您关心时区信息,我会将其分开存储,并且仅在最后一个可能的情况下(例如,在显示之前)将utc转换为本地时间

也许您根本不需要关心,可以使用运行程序的计算机或用户的浏览器(如果是网络应用程序)使用本地时区信息。