SQLAlchemy 下处理时区问题

嗯……随着我们项目越做越大了现在该考虑国际化啦,首先遇到的就是时区问题。

一般我们都会在一个表中加入类似 created_at 这样的字段,目的是记录这条记录到底是什么时候被创建的,但是我们这里存哪个时区的时间好呢?

直接存 UTC

这是一种做法,我在 Flask 的书上看见他也是这么做的,不管 3721 直接用 datetime.datetime.utcnow() 作为值传入数据库。那样不管数据库上到底是什么时间,我们知道数据库所有的时间都是 UTC,然后让前端通过取浏览器的时区对这个世间进行转换。

这么做的问题是读数据的应用可能不止你自己一人,当别人也想读该数据库中的内容时,他看见出来的时间和自己预料的不一致,可能会对别人造成困惑~~(全看悟性)~~。一种方法就和你的队友约定好你们到底使用哪里的时区。

就用开发者自己的时区

这种做法和第一种是一样的,可能你和你的队友都需要商量下方案。

使用数据库的时区

数据库也是有自己的时区的,一般来讲 MySQL 的话会直接复用 HOST 的时区,那么如何以 MySQL 的时区作为其默认值呢?

你可以使用 db.func.now() 方法作为其默认值,注意是 db.func.now() 而不是 db.func.now

那当我们只有数据库普通的用户权限的时候,能不能修改当前连接的时区呢?你可以执行 -

SET time_zone = '+8:00';
flush privileges;

之后你通过 db.func.now() 拿到的时区就肯定是东八区了。

还有一个问题是我们上面两句话当我使用 Flask-SQLAlchemy 的时候该在什么时候执行?

最好的方案其实是使用一个特殊的 driver: mysqlconnector,这个好像是官方出的?

它可以在连接时就指定好使用的时区,具体可以参考 Connector/Python Connection Arguments

当要应用到 Flask-SQLAlchemy 中时,你可能需要重写一个方法。

from flask.ext.sqlalchemy import SQLAlchemy as SQLAlchemyOriginal

class SQLAlchemy(SQLAlchemyOriginal):

    def apply_driver_hacks(self, app, info, options):
        if info.drivername == 'mysql+mysqlconnector':
            options['connect_args'] = {'time_zone': DATABASE_TIMEZONE}
        super(SQLAlchemy, self).apply_driver_hacks(app, info, options)

Tags :