微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

使 SQLAlchemy 使用本地时区作为数据库生成的日期

如何解决使 SQLAlchemy 使用本地时区作为数据库生成的日期

在我的 sqlAlchemy 模型中,数据库 (sqlite) 在写操作期间更新时间戳列:

class DBObject(declarative_base()):
    __tablename__ = 'dbobj'
    id = Column(Integer,primary_key=True,autoincrement=True)
    date = Column(DateTime(timezone=True))
    text = Column(String(64))
    created_at = Column(DateTime(timezone=True),server_default=func.Now())
    updated_at = Column(DateTime(timezone=True),server_default=func.Now(),onupdate=func.Now())

engine = create_engine('sqlite:///:memory:')
DBObject.Metadata.create_all(bind=engine)

然而,这似乎并没有考虑到时区。如何让 sqlAlchemy 将这些时间戳转换为我的本地时区? (我知道 sqlite 仅适用于 UTC)

fmt = '%Y-%m-%d %H:%M:%s'
print(f"tzone  = {time.timezone}s")  # Local timezone offset to UTC.
print(f"Now    = {datetime.Now().strftime(fmt)}")  # Current local time.
s = Session(bind=engine)
try:

    # Create new entry.
    s.add(DBObject(date=datetime.Now(),text='created'))
    s.flush()

    # Wait a bit
    time.sleep(1)

    # Update entry.
    obj = s.query(DBObject).one()
    obj.text = 'updated'
    s.flush()

    # Read entry and print dates.
    obj = s.query(DBObject).one()
    print(f"date   = {obj.date.strftime(fmt)}")
    print(f"create = {obj.created_at.strftime(fmt)}")
    print(f"update = {obj.updated_at.strftime(fmt)}")
finally:
    s.close()

实际输出

tzone  = -3600s
Now    = 2021-01-26 18:40:15
date   = 2021-01-26 18:40:15
create = 2021-01-26 17:40:15
update = 2021-01-26 17:40:16

预期输出

tzone  = -3600s
Now    = 2021-01-26 18:40:15
date   = 2021-01-26 18:40:15
create = 2021-01-26 18:40:15
update = 2021-01-26 18:40:16

我还尝试了什么:

  • 删除timezone=True中的DateTime
  • 使用sqlalchemy.TIMESTAMP(有或没有timezone=True
  • 使用 default 而不是 server_default
  • 使用 datetime.utcNow 而不是 func.Now()

请注意,这包括对非常相似的 stackoverflow 问题(例如 SQLAlchemy default DateTime)的解决方案。 这些似乎都没有任何区别。 sqlAlchemy 和 sqlite 函数似乎都只能在 UTC 中工作。我发现的唯一解决方案是完全删除他们的日期时间功能

class DBObject(declarative_base()):
    __tablename__ = 'dbobj'
    id = Column(Integer,autoincrement=True)
    date = Column(DateTime)
    text = Column(String(64))
    created_at = Column(DateTime,default=datetime.Now)
    updated_at = Column(DateTime,default=datetime.Now,onupdate=datetime.Now)

在这种情况下,我得到了预期的输出,但我猜所有数据库本机时间函数仍将关闭,因此无法在任何 sql 查询中使用。

如何告诉 sqlAlchemy 和/或 sqlite 在本地时区返回日期时间对象? 有什么办法可以使用这两者并让数据库分配日期无需一直转换为 UTC 或从 UTC 转换?我好像遗漏了什么。

奖金要求:

使用 s.query(DBObject).all() 读取需要返回与使用熊猫读取相同的日期:pd.read_sql(s.query(DBObject).statement,s.bind)

版本:

  • Python:3.7.9
  • sqlAlchemy:1.3.22
  • sqlite:2.6.0

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。