我认为这个测试很有趣,虽然它没有回答你的问题,但它确实将节点库排除在等式之外。
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 中的每一个以测试一些不同的本地时区,然后插入会话时区以跟踪哪个时区创建了哪个值。然后我再次选择它们并将每个时区设置为我的会话时区,以显示插入会话的时区和选择会话的时区如何交互。
然后我再次做整个事情,就像以前一样,但不是 DATETIME 我第二次创建带有 TIMESTAMP 字段的列。
我在一个 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,但显然没有针对 SELECT sesson 的时区进行更正。
另一方面,时间戳的行为不同。在这些情况下,时间戳在选择时会正确转换为 SELECT 的会话时间。我认为这通常是数据库客户端所期望的行为(我设置了一个会话时区,所以显示该会话时区中的日期)。
简而言之,如果要存储本地时间,请使用 datetime。如果要存储“绝对时间”,请使用时间戳。不确定这是否是一个好规则,但根据我的测试,这似乎是一个好方法。
当然,正如您所指出的,客户端仍然必须设置他们希望使用的时区。将所有内容设置为使用相同的时区可以避免整个问题:)