Bookshelf.js/Knex.js对UTC DATETIME列太"有用"了

smi*_*lli 14 javascript mysql datetime bookshelf.js knex.js

我有一个MySQL表,这个表有一个DATETIME名为的列datetime_utc.正如您所料,它是UTC的日期和时间.在我的Bookshelf模型中,我定义了一个虚拟的getter,它使用Moment.js将其转换为ISO 8601字符串格式.我的模型看起来像这样:

bookshelf.plugin('virtuals');

exports.MyModel = bookshelf.Model.extend({
    tableName : 'my_table',
    idAttribute : 'id',
    virtuals : {
        datetime_iso : {
            get : function () {
                return moment.utc(this.get('datetime_utc')).format();
            }
        }
    }
});
Run Code Online (Sandbox Code Playgroud)

问题是,当Bookshelf(或支持它的底层Knex)看到DATETIME列时,它会在将值new Date(...)提供给我的代码之前将值包装在a中.由于日期的值是UTC,但Date构造函数假定值在服务器的本地非UTC时区,我最终得到一个Date对象,该对象在错误的时区中具有正确的日期.一旦Moment在此日期开始工作,所有值都将按固定的小时数关闭.

我通过查找Date对象并将日期组件直接分解为Moment构造函数来解决这个问题.但感觉很糟糕:

get : function () {
    var dt = this.get('datetime_utc');

    if (dt instanceof Date) {
        dt = [
            dt.getFullYear(), dt.getMonth(), dt.getDate(),
            dt.getHours(), dt.getMinutes(), dt.getSeconds()
        ];
    }

    return moment.utc(dt).format();
}
Run Code Online (Sandbox Code Playgroud)

是否有更YYYY-MM-DD HH:MM:SS简洁的方法从Bookshelf 获取非包装的字符串值,或者从Date中创建新Moment对象的速记,时区被忽略/ munged到UTC?

smi*_*lli 23

事实证明,这不是由Knex或Bookshelf引起的,而是由底层的node-mysql库引起的.有一个叫连接属性timezone将被附加到每个DATETIME,DATE,TIMESTAMP,和NEWDATE前值被解析成Date对象.

Knex在初始化时会将此属性传递给node-mysql:

require('knex')({
    "client": "mysql",
    "connection": {
        "host": "...",
        "user": "...",
        "password": "...",
        "database": "...",
        "timezone": "UTC"    <-- This is the culprit
    }
});
Run Code Online (Sandbox Code Playgroud)