我正在使用SQLAlchemy,我还不确定我将使用哪个数据库,因此我希望尽可能保持与数据库无关。如何在不将自己绑定到特定数据库的情况下将时区感知日期时间对象存储在数据库中?现在,我确定时间是UTC,然后我将它们存储在数据库中,并在显示时转换为本地化,但感觉不够优雅和脆弱。是否有一种与数据库无关的方法来从SQLAlchemy中获取时区感知日期时间而不是从数据库中获取天真的数据时间对象?
答案 0 :(得分:42)
DateTime
列时间有一个timezone
参数,因此存储时区感知datetime
对象没有问题。但是我发现使用简单类型装饰器自动将存储的datetime
转换为UTC是很方便的:
from sqlalchemy import types
from dateutil.tz import tzutc
from datetime import datetime
class UTCDateTime(types.TypeDecorator):
impl = types.DateTime
def process_bind_param(self, value, engine):
if value is not None:
return value.astimezone(tzutc())
def process_result_value(self, value, engine):
if value is not None:
return datetime(value.year, value.month, value.day,
value.hour, value.minute, value.second,
value.microsecond, tzinfo=tzutc())
注意,当您偶然使用朴素datetime
时,这表现得很好(意味着它会引发ValueError)。
答案 1 :(得分:2)
我正在通过在所有内部实例中使用UTC来满足在代码中具有日期时间意识的愿望。我想到的唯一问题是在读取数据库时。尽管将datetime-aware写入数据库,但在检索格式时还是幼稚的。我的解决方法是:
import pytz
dt = mydb.query.filter_by(name='test').first().last_update.replace(tzinfo=pytz.utc)
dt
是将存储以日期时间格式检索的last_update的变量mydb
是我的数据库表的名称name
是表中的列之一last_update
是以日期时间格式存储的列诀窍是replace(tzinfo=pytz.utc)
答案 2 :(得分:0)
SQLAlchemy文档具有a recipe for this:
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