ali*_*lif 42 python postgresql timezone datetime sqlalchemy
SQLAlchemy的DateTime
类型允许timezone=True
参数将非天真的日期时间对象保存到数据库,并返回它.有没有办法修改tzinfo
SQLAlchemy传入的时区,所以它可能是,例如,UTC?我意识到我可以使用default=datetime.datetime.utcnow
; 然而,这是一个天真的时间,很乐意接受有人在一个天真的基于timezone=True
本地时间的日期时间,即使我使用它,因为它使本地或UTC时间不天真没有基准时区来规范化它.我已经尝试过(使用pytz)使日期时间对象不天真,但是当我将它保存到数据库时,它又回归天真.
注意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()
Run Code Online (Sandbox Code Playgroud)
(1,datetime.datetime(2009,1,6,0,9,36,891887))
row[1].utcoffset()
Run Code Online (Sandbox Code Playgroud)
datetime.timedelta(-1,64800)#这是我的本地时间偏移!!
datetime.datetime.now(tz=pytz.timezone("US/Central"))
Run Code Online (Sandbox Code Playgroud)
datetime.timedelta(-1,64800)
datetime.datetime.now(tz=pytz.timezone("UTC"))
Run Code Online (Sandbox Code Playgroud)
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()
Run Code Online (Sandbox Code Playgroud)
...
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
Run Code Online (Sandbox Code Playgroud)
...
真的#这次甚至都没有为数据库保存时区
iny*_*iny 18
http://www.postgresql.org/docs/8.3/interactive/datatype-datetime.html#DATATYPE-TIMEZONES
所有时区感知日期和时间都以UTC格式存储在内部.在显示给客户端之前,它们将在timezone配置参数指定的区域中转换为本地时间.
使用postgresql存储它的唯一方法是单独存储它.
One way to solve this issue is to always use timezone-aware fields in the database. But note that the same time can be expressed differently depending on the timezone, and even though this is not a problem for computers it is very inconvenient for us:
2003-04-12 23:05:06 +01:00
2003-04-13 00:05:06 +02:00 # This is the same time as above!
Run Code Online (Sandbox Code Playgroud)
Also Postgresql stores all timezone-aware dates and times internally in UTC. They are converted to local time in the zone specified by the timezone configuration parameter before being displayed to the client.
Instead, I recommend to use UTC
timestamps both throughout the app and timezone-naive dates and times in the database, and only convert them to users local timezone before user sees them.
This strategy lets you have the cleanest code, avoiding any timezone conversions and confusions, and makes your database and app work consistently independent of the "local timezone" differences. For example, you might have your development machine and production server running on cloud in different timezones.
To achieve this, tell Postgresql that you want to see timezones in UTC before initializing the engine.
In SqlAlchemy you do it like this:
engine = create_engine(..., connect_args={"options": "-c timezone=utc"})
Run Code Online (Sandbox Code Playgroud)
And if you are using tornado-sqlalchemy you can use:
factory = make_session_factory(..., connect_args={"options": "-c timezone=utc"})
Run Code Online (Sandbox Code Playgroud)
Since we use all UTC timezones everywhere, we simply use timezone-naive dates and times in the model:
created_at = Column(DateTime, default=datetime.utcnow)
updated_at = Column(DateTime)
Run Code Online (Sandbox Code Playgroud)
And the same in case if you are using alembic:
sa.Column('created_at', sa.DateTime()),
sa.Column('updated_at', sa.DateTime()),
Run Code Online (Sandbox Code Playgroud)
And in the code use UTC time:
from datetime import datetime
...
model_object.updated_at = datetime.now(timezone.utc)
Run Code Online (Sandbox Code Playgroud)
小智 5
建议使用以下结构在数据库中存储 UTC 日期和时间数据,并防止存储没有此类位置信息的数据。
import datetime
from sqlalchemy import DateTime
from sqlalchemy.types import TypeDecorator
class TZDateTime(TypeDecorator):
"""
A DateTime type which can only store tz-aware DateTimes.
"""
impl = DateTime(timezone=True)
def process_bind_param(self, value, dialect):
if isinstance(value, datetime.datetime) and value.tzinfo is None:
raise ValueError('{!r} must be TZ-aware'.format(value))
return value
def __repr__(self):
return 'TZDateTime()'
Run Code Online (Sandbox Code Playgroud)
存储在数据库中的值应定义如下:
import datetime
import pytz
def tzware_datetime():
"""
Return a timezone aware datetime.
:return: Datetime
"""
return datetime.datetime.now(pytz.utc)
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
43137 次 |
最近记录: |