在mysql中插入行时,当前时间戳不正确,我使用的是aws rds

bfrts1fy  于 2021-06-17  发布在  Mysql
关注(0)|答案(3)|浏览(398)

编辑:这是我使用node-mysql2的mysql库的一个问题
我正在使用awsrds来托管mysql数据库。
我的数据库中有一列的定义如下 createdAt TIMESTAMP DEFAULT CURRENT_TIMESTAMP 当我在美国东部时间下午4:43插入一行时,我得到该列的以下值 2018-12-27T02:43:32.000Z 当我试着把这个值转换成est时 12/26/2018, 9:43:32 PM 这是不正确的。
我是否做了一些不正确的事情,或者需要配置一些东西?

dly7yett

dly7yett1#

决不能使用任何数据库日期、时间或时间戳格式。oracle、mysql和ms sql server是否提供了本问题中所述的“帮助”。当我们从变速箱工厂装运的变速箱在装运前到达装配厂时,我非常艰难地学会了这一点。在一家大型汽车公司,物流是巨大的——每天有超过100万英里的18轮车。安排得好是一大笔钱,所以我们被告知现在就去解决它!
结果发现,操作系统认为它在一个时区,数据库确信它在另一个时区,当我们登录时,每个用户id都被设置为不同的时区。
唯一的解决方案是将所有时间记录为gmt毫秒。这样,您就可以在一个时间间隔内检索事件、比较时间、计算时间间隔以及合并来自多个源的数据。您必须担心以对每个用户都有意义的方式显示时间,但至少您不必担心底层计算的愚蠢。
永远不要,永远不要使用数据库时间戳-他们搞笑的方式把你搞砸了。

oknwwptz

oknwwptz2#

我觉得这个测试很有趣,虽然它没有回答你的问题,但是它确实把节点库从等式中去掉了,我觉得它很有趣。

CREATE DATABASE IF NOT EXISTS test;
USE test;

CREATE TEMPORARY TABLE t (
  id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
  created DATETIME DEFAULT CURRENT_TIMESTAMP,
  tz varchar(32)
);

select "datetime";

SET time_zone = "CST6CDT";
insert into t (tz) values (@@SESSION.time_zone);

SET time_zone = "EST5EDT";
insert into t (tz) values (@@SESSION.time_zone);

SET time_zone = "UTC";
insert into t (tz) values (@@SESSION.time_zone);

SET time_zone = "CST6CDT";
select *, @@SESSION.time_zone FROM t;

SET time_zone = "EST5EDT";
select *, @@SESSION.time_zone FROM t;

SET time_zone = "UTC";
select *, @@SESSION.time_zone FROM t;

DROP TEMPORARY TABLE t;

select "timestamp";

CREATE TEMPORARY TABLE t (
  id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
  created TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
  tz varchar(32)
);

SET time_zone = "CST6CDT";
insert into t (tz) values (@@SESSION.time_zone);

SET time_zone = "EST5EDT";
insert into t (tz) values (@@SESSION.time_zone);

SET time_zone = "UTC";
insert into t (tz) values (@@SESSION.time_zone);

SET time_zone = "CST6CDT";
select *, @@SESSION.time_zone FROM t;

SET time_zone = "EST5EDT";
select *, @@SESSION.time_zone FROM t;

SET time_zone = "UTC";
select *, @@SESSION.time_zone FROM t;

在这里,我创建了一个临时表 DEFAULT CURRENT_TIMESTAMP 列。我将会话变量分别设置为cst、est和utc,以测试一些不同的本地时区,然后插入会话时区以跟踪哪个时区创建了哪个值。然后,我再次选择它们,并将每个时区设置为我的会话时区,以显示insert会话的时区和select会话的时区是如何交互的。
然后,我再次执行整个操作,与之前完全一样,但是我第二次创建了带有timestamp字段的列,而不是datetime。
我在docker容器中运行它只是为了测试,首先是:

docker run --rm -d -e MYSQL_ALLOW_EMPTY_PASSWORD=true --name mysql mysql

但是,从任何可以访问服务器的mysql客户机上运行都应该非常容易;这是我的 docker exec 调用:

$ docker exec -i mysql mysql -t  < t.sql
+----------+
| datetime |
+----------+
| datetime |
+----------+
+----+---------------------+---------+---------------------+
| id | created             | tz      | @@SESSION.time_zone |
+----+---------------------+---------+---------------------+
|  1 | 2018-12-27 11:07:05 | CST6CDT | CST6CDT             |
|  2 | 2018-12-27 12:07:05 | EST5EDT | CST6CDT             |
|  3 | 2018-12-27 17:07:05 | UTC     | CST6CDT             |
+----+---------------------+---------+---------------------+
+----+---------------------+---------+---------------------+
| id | created             | tz      | @@SESSION.time_zone |
+----+---------------------+---------+---------------------+
|  1 | 2018-12-27 11:07:05 | CST6CDT | EST5EDT             |
|  2 | 2018-12-27 12:07:05 | EST5EDT | EST5EDT             |
|  3 | 2018-12-27 17:07:05 | UTC     | EST5EDT             |
+----+---------------------+---------+---------------------+
+----+---------------------+---------+---------------------+
| id | created             | tz      | @@SESSION.time_zone |
+----+---------------------+---------+---------------------+
|  1 | 2018-12-27 11:07:05 | CST6CDT | UTC                 |
|  2 | 2018-12-27 12:07:05 | EST5EDT | UTC                 |
|  3 | 2018-12-27 17:07:05 | UTC     | UTC                 |
+----+---------------------+---------+---------------------+
+-----------+
| timestamp |
+-----------+
| timestamp |
+-----------+
+----+---------------------+---------+---------------------+
| id | created             | tz      | @@SESSION.time_zone |
+----+---------------------+---------+---------------------+
|  1 | 2018-12-27 11:07:05 | CST6CDT | CST6CDT             |
|  2 | 2018-12-27 11:07:05 | EST5EDT | CST6CDT             |
|  3 | 2018-12-27 11:07:05 | UTC     | CST6CDT             |
+----+---------------------+---------+---------------------+
+----+---------------------+---------+---------------------+
| id | created             | tz      | @@SESSION.time_zone |
+----+---------------------+---------+---------------------+
|  1 | 2018-12-27 12:07:05 | CST6CDT | EST5EDT             |
|  2 | 2018-12-27 12:07:05 | EST5EDT | EST5EDT             |
|  3 | 2018-12-27 12:07:05 | UTC     | EST5EDT             |
+----+---------------------+---------+---------------------+
+----+---------------------+---------+---------------------+
| id | created             | tz      | @@SESSION.time_zone |
+----+---------------------+---------+---------------------+
|  1 | 2018-12-27 17:07:05 | CST6CDT | UTC                 |
|  2 | 2018-12-27 17:07:05 | EST5EDT | UTC                 |
|  3 | 2018-12-27 17:07:05 | UTC     | UTC                 |
+----+---------------------+---------+---------------------+

如您所见,datetime总是存储在会话的本地时间中。我不清楚如何知道是否将其转换为不同的时区,因为时区显然在内部存储为utc,但显然没有针对选定的sesson时区进行更正。
另一方面,时间戳的行为不同。在这些情况下,时间戳在被选中时会正确地转换为select的会话时间。我认为这通常是数据库客户机所期望的行为(我设置了会话时区,所以显示该会话时区中的日期)。
简而言之,如果要存储本地时间,请使用datetime。如果要存储“绝对时间”,请使用时间戳。不确定这是否是一个好的规则,但根据我的测试,这似乎是一个很好的方法。
当然,正如您所指出的,客户机仍然需要设置他们希望使用的时区。将所有内容设置为使用同一时区可以避免整个问题:)

xu3bshqb

xu3bshqb3#

这不是aws或mysql的问题
我发现了问题所在,node-mysql2决定转换时间戳。我不明白它在做什么或者为什么。
我用来修好它的背景是

let options = {
    ...,
    timezone: 'UTC', // Interpret all received timestamps as UTC. Otherwise local timezone is assumed.
    dateStrings: [
        'DATE', // DATE's are returned as strings (otherwise they would be interpreted as YYYY-MM-DD 00:00:00+00:00)
        'DATETIME' // DATETIME's return as strings (otherwise they would interpreted as YYYY-MM-DD HH:mm:ss+00:00)
    ]
}

相关问题