从昨天中午开始就在做 node 的项目的过程中,发现 sql 查询时发现有个日期时间的字段返回的值与数据表里面真实的时间值对不上(两个时间之间相差8个小时),为了解决这个问题花了大量的时间(当然中间因其他的事耽搁昨天一下午的时间),现在终于把这个问题给研究透了。现在我将这个问题的解决过程记录下来。
编写时的环境
- 操作系统:windows 10
- node 版本:v8.9.1
- 采用语言:typeScrpit
- 连接 mysql 的依赖库:knex
解决的过程
当遇到这个问题时,凭经验告诉我是时区出了问题,可 nodeJs 的时区与 mysql 的时区并不直接的关系,与 mysql 直接有关系点应该是从与 mysql 建立连接到 sql 执行之后返回结果的这个过程。于是呼我在 knex 的官方文档中查询有关时区的设置,但在官方的文档上对时区的设置只看到是在建立连接的时候,如下段代码:
dbClient = require('knex')({ client: 'mysql', connection: {……}, pool: { min: 2, max: 10, afterCreate: function (conn, done) { // in this example we use pg driver's connection API conn.query('set global time_zone = "+8:00";', function (err) { if (err) { // first query failed, return error and don't try to make next query done(err, conn); } else { // do the second query... conn.query('select curtime();', function (err,data) { // if err is not falsy, connection is discarded from pool // if connection aquire was triggered by a query the error is passed to query promise console.log('query', data); done(err, conn); }); } }); } } });
可加上之后,再执行查询发现上面的设置并没有起到作用,依旧是8小时的时区问题,最后没办法就去找谷歌帮忙了,最后在谷歌找到一点有关 mysql 的线索,那就是 mysql 中有个叫 CONVERT_TZ 函数,这个函数可用于在查询时对某个日期时间类型(date / datetime)的字段做时区的处理,于是呼我在这个函数手写 SQL 使用 knex 中的 raw 方法做测试
dbClient.raw("SELECT *, CONVERT_TZ(`Date`,'+00:00','+08:00') AS Date FROM tableName") .then(data => { resolve(data); });
执行结果让我惊喜万分,返回的时间值已经回归到正确的时间值,可另一个问题又来了,上面代码执行的数据结构是一个里面有 FieldPacket 和 RowDataPacket 两种不同数据结构的数组,而 RowDataPacket 数组里面的数据才是我真正想要的数据,要怎么办呢,难道还要写一段代码去取吗,这样感觉总是不怎么好吧。于是呼又回到官网的文档上去找寻答案, 皇天不负有心人终于找到最好的解决方法,就是将 raw 方法与平时用的 select 方法做一个整合代码如下
var fields = "*, CONVERT_TZ(`Date`,'+00:00','+08:00') AS Date" dbClient(tableName).select(dbClient.raw(fields)).where(parmas).orderBy(orderField, orderType).limit(limit).then(data => { resolve(data); });
最后执行完的结果就是真正想要的数据。问题成功得到解决。
转载请注明:隨習筆記 » NodeJs笔记:sql查询时遇到时区问题