SQLAlchemy的DateTime对象只能是朴素的吗?
我正在使用SQLAlchemy,但还没决定用哪个数据库,所以我想尽量不依赖特定的数据库。我想知道怎么才能把带时区的日期时间对象存储到数据库里,而不和某个特定的数据库绑定在一起。目前,我在存储之前确保时间是UTC格式,然后在显示时再转换成本地时间,但这样感觉不太优雅,也不太稳定。有没有一种不依赖数据库的方法,可以从SQLAlchemy中获取带时区的日期时间,而不是从数据库中得到没有时区的日期时间对象呢?
3 个回答
1
SQLAlchemy的文档里有一个解决方案,可以帮助你处理这个问题:
import datetime
class TZDateTime(TypeDecorator):
impl = DateTime
def process_bind_param(self, value, dialect):
if value is not None:
if not value.tzinfo:
raise TypeError("tzinfo is required")
value = value.astimezone(datetime.timezone.utc).replace(
tzinfo=None
)
return value
def process_result_value(self, value, dialect):
if value is not None:
value = value.replace(tzinfo=datetime.timezone.utc)
return value
2
我想在我的代码中使用UTC时间来处理日期和时间,这样可以确保所有内部的时间都是一致的。唯一的问题是,当我从数据库中读取数据时,尽管我把日期时间存储得很准确,但取出来的时候却是没有时区信息的。这让我很困扰。为了解决这个问题,我做了以下处理:
import pytz
dt = mydb.query.filter_by(name='test').first().last_update.replace(tzinfo=pytz.utc)
dt
是一个变量,用来存储从数据库中获取的最后更新时间,格式是日期时间。mydb
是我数据库表的名字。name
是表中的一个列名。last_update
是一个存储日期时间格式的列。
解决这个问题的关键在于使用replace(tzinfo=pytz.utc)
这段代码。
46
在DateTime
列中,有一个timezone
参数,这样就可以存储带有时区信息的datetime
对象,没什么问题。不过,我发现用一个简单的类型装饰器自动把存储的datetime
转换成UTC时间非常方便:
from sqlalchemy import types
from datetime import datetime, timezone
class UTCDateTime(types.TypeDecorator):
impl = types.DateTime
def process_bind_param(self, value, engine):
if value is None:
return
if value.utcoffset() is None:
raise ValueError(
'Got naive datetime while timezone-aware is expected'
)
return value.astimezone(timezone.utc)
def process_result_value(self, value, engine):
if value is not None:
return value.replace(tzinfo=timezone.utc)
需要注意的是,如果你不小心使用了没有时区信息的datetime
(也就是所谓的“天真”datetime
),它会抛出一个ValueError错误。