在 Knex dateTime()/MySQL DATETIME 字段中存储 Node.js 日期

Storing a Node.js Date in a Knex dateTime()/MySQL DATETIME field

我在寻找 Node.js、knex 和 MySQL(通过 Bookshelf)通用的日期格式时遇到了一些问题。

我使用 Knex 架构构建器设置了 table:

knex.schema.createTableIfNotExists("examples", function (table) {
    ...
    table.dateTime("some_datetime");
})

这将在 MySQL 中创建一个具有 DATETIME 类型的列。

我有一个 Bookshelf 模型来表示这个(这里省略了所有样板文件),我尝试使用内置的 Date.now() 作为值:

exampleModel.save({
    some_datetime: Date.now()
})

在 Knex 中打开调试后,我看到查询实际上是在尝试插入一个以毫秒为单位的纪元时间戳(“...”为简洁起见,我的):

{ ...
  bindings: [ 1485644012453, ... ],
  sql: 'update `examples` set `some_datetime` = ? where `id` = ?' }

但这是不正确的,因为在这种情况下 MySQL expects you to use FROM_UNIXTIME,因此数据库中的结果日期当然是好的 0000-00-00 00:00:00

我应该在这里做什么才能使这一切保持一致?

我在这里找不到共同点。我的直觉是在 Knex 中使用 dateTime,在 Node 中使用 Date.now(),在 MySQL 中使用 DATETIME,但这是不正确的。

需要说明的是:这个问题不一定关注什么是哲学上正确的——目前我实际上无法弄清楚如何在 [=42] 的数据库中存储 date/times =]全部。我正在寻找一个 工作 组合,语义正确性只是一个奖励。

Javascript 函数 Date.now() returns 以毫秒为单位的纪元。 Mysql 驱动程序,knex 用于发送查询,希望您将 ISO8061 字符串或 Date() 对象传递到 DATETIME 列。

Date objects are converted to 'YYYY-mm-dd HH:ii:ss' strings

https://github.com/mysqljs/mysql

所以不用 Date.now() 使用 new Date()new Date().toISOString()

编辑:

只是检查 mysql 是否真的接受 .toISOString() 输出,因为我无法从文档中找到关于它的提及 https://dev.mysql.com/doc/refman/5.7/en/date-and-time-type-overview.html

MariaDB [(none)]> select CAST('2017-01-30T16:49:19.278Z' AS DATETIME);
+----------------------------------------------+
| CAST('2017-01-30T16:49:19.278Z' AS DATETIME) |
+----------------------------------------------+
| 2017-01-30 16:49:19                          |
+----------------------------------------------+
1 row in set, 1 warning (0.00 sec)

看起来确实如此。耶!一切顺利。

EDIT2:实际上,在某些情况下,使用 .toISOString() 会导致警告和错误,因此插入 UTC DATETIME 列 .toISOString().replace('Z','').replace('T', ' ') 应该......或任何其他首选方法使 UTC 日期时间对象转换为 yyyy-MM-dd HH:mm:ss.

格式

此外,如果您使用的是 TIMESTAMP 列类型并且想要将 UTC 时间插入数据库,那么将数据库会话设置为 UTC 也很重要。否则,javascript 时间戳将被解释为本地数据库时间,并在存储之前将其转换为 UTC。

CREATE TABLE test (descr TEXT, dt DATETIME, ts TIMESTAMP);

SET time_zone = '+8:00';
INSERT INTO test (descr, dt, ts) VALUES 
  ('session tz +08:00 insert local times', '2020-01-01T00:00:00', '2020-01-01T00:00:00');

SET time_zone = '+0:00';
INSERT INTO test (descr, dt, ts) VALUES 
  ('session tz +00:00 insert local times', '2020-01-01 00:00:00', '2020-01-01 00:00:00');


SET time_zone = '+02:00';
select 'server local time:', now();
select * from test;

SET time_zone = '+08:00';
select 'server local time:', now();
select * from test;
---

**Query #1**

    SET time_zone = '+02:00';

There are no results to be displayed.

---
**Query #2**

    select 'server local time:', now();

| server local time: | now()               |
| ------------------ | ------------------- |
| server local time: | 2020-05-10 16:38:26 |

---
**Query #3**

    select * from test;

| descr                                | dt                  | ts                  |
| ------------------------------------ | ------------------- | ------------------- |
| session tz +08:00 insert local times | 2020-01-01 00:00:00 | 2019-12-31 18:00:00 |
| session tz +00:00 insert local times | 2020-01-01 00:00:00 | 2020-01-01 02:00:00 |

---
**Query #4**

    SET time_zone = '+08:00';

There are no results to be displayed.

---
**Query #5**

    select 'server local time:', now();

| server local time: | now()               |
| ------------------ | ------------------- |
| server local time: | 2020-05-10 22:38:26 |

---
**Query #6**

    select * from test;

| descr                                | dt                  | ts                  |
| ------------------------------------ | ------------------- | ------------------- |
| session tz +08:00 insert local times | 2020-01-01 00:00:00 | 2020-01-01 00:00:00 |
| session tz +00:00 insert local times | 2020-01-01 00:00:00 | 2020-01-01 08:00:00 |

---

View on DB Fiddle

显示如何存储和读取 TIMESTAMP 实际上总是作为当地时间处理,DATATIME 独立于 time_zone 数据库会话的设置。

通过快速测试,即使在 mysql 8.

上,我也无法使 yyyy-MM-dd HH:mm:ss+zz:zz 类型的时间戳/日期时间正常工作

您可以使用 Knex.js 的内置 now() 函数代替 Date.now()

const knexfile = require('../../knexfile');
const knex = require('knex')(knexfile.development);
const date = knex.fn.now();

选择:

const knexfile = require('../../knexfile');
const knex = require('knex')(knexfile.development);
knex.raw('CURRENT_TIMESTAMP');