为什么 SELECT in (IDENTIC: [version MySQL + SESSION.sql_mode + system_time_zone]) return 在 CentOs 7 中为 NULL 但在 W10 中为 GOAL + WARNING?

why SELECT in (IDENTIC: [version MySQL + SESSION.sql_mode + system_time_zone]) return NULL in CentOs 7 but GOAL + WARNING on W10?

我知道警告是由夏令时发出的,但为什么查询的结果不同:

SELECT CONVERT_TZ('2002-10-23T15:57:03Z', 'SYSTEM', 'America/Bogota')

当我在 CentOs 7 中 运行 QUERY 时:

[VERSION()] => 5.7.33
[@@SESSION.sql_mode] => ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION
[@@session.time_zone] => GMT

从MySQL我得到

NULL

当我 运行 Windows 10 中的查询时:

[VERSION()] => 5.7.33
[@@SESSION.sql_mode] => ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION
[@@session.time_zone] => GMT

从MySQL我得到

[CONVERT_TZ('2002-10-23T15:57:03Z', 'GMT', 'America/Bogota')] => 2002-10-23 10:57:03
WARNING (
    [Level] => Warning
    [Code] => 1292
    [Message] => Truncated incorrect datetime value: '2002-10-23T15:57:03Z'
)

如果两个服务器的环境相同,为什么结果不同?

在 Windows 我没有 my.ini 这是 CentOs 7 中的文件 my.ini:

# For advice on how to change settings please see
# http://dev.mysql.com/doc/refman/5.7/en/server-configuration-defaults.html

[mysqld]
performance-schema=0
#
# Remove leading # and set to the amount of RAM for the most important data
# cache in MySQL. Start at 70% of total RAM for dedicated server, else 10%.
# innodb_buffer_pool_size = 128M
#
# Remove leading # to turn on a very important data integrity option: logging
# changes to the binary log between backups.
# log_bin
#
# Remove leading # to set options mainly useful for reporting servers.
# The server defaults are faster for transactions and fast SELECTs.
# Adjust sizes as needed, experiment to find the optimal values.
# join_buffer_size = 128M
# sort_buffer_size = 2M
# read_rnd_buffer_size = 2M
datadir=/var/lib/mysql
socket=/var/lib/mysql/mysql.sock

# Disabling symbolic-links is recommended to prevent assorted security risks
symbolic-links=0

log-error=/var/log/mysqld.log
pid-file=/var/run/mysqld/mysqld.pid
innodb_buffer_pool_size=53477376
max_allowed_packet=268435456
open_files_limit=40000
innodb_file_per_table=1

default_storage_engine=MyIsam
default_tmp_storage_engine=MyIsam
character_set_server=utf8mb4
collation_server=utf8mb4_general_ci

MySQL 在时区方面有点蹩脚。

无法识别结尾的 Z,但我认为您只会收到警告。

您是否加载了时区 table? (我不知道这是否是您安装的一个单独步骤。请参阅 https://dev.mysql.com/downloads/timezones.html

这样效果更好,但需要知道调整因子:

mysql> SELECT CONVERT_TZ('2002-10-23T15:57:03', 'SYSTEM', '-05:00');
+-------------------------------------------------------+
| CONVERT_TZ('2002-10-23T15:57:03', 'SYSTEM', '-05:00') |
+-------------------------------------------------------+
| 2002-10-23 17:57:03                                   |
+-------------------------------------------------------+

时间戳

TIMESTAMP只不过是一个数字——从1970年开始的秒数。但是,当storing/fetching时,基于某些设置的时区信息是从系统时间to/from UTC:

mysql> SHOW VARIABLES LIKE '%zone%';
+------------------+--------+
| Variable_name    | Value  |
+------------------+--------+
| system_time_zone | PDT    |
| time_zone        | SYSTEM |
+------------------+--------+
2 rows in set (0.01 sec)

SYSTEM基于OS设置。

日期时间

DATETIME(以及仅限日期的 DATE)本质上是 您的 墙上的时钟图片。也就是说,除了您在这里可以看到的内容之外,没有 信息存储在其中:

mysql> SELECT NOW();
+---------------------+
| NOW()               |
+---------------------+
| 2021-04-19 09:35:23 |
+---------------------+
1 row in set (0.00 sec)

没有存储时区信息。字符串中也没有任何 TZ 信息:

mysql> SELECT HOUR('2021-04-19 09:35:23 -07:00');
+------------------------------------+
| HOUR('2021-04-19 09:35:23 -07:00') |
+------------------------------------+
|                                  9 |
+------------------------------------+
1 row in set, 1 warning (0.00 sec)

mysql> show warnings;
+---------+------+--------------------------------------------------------------+
| Level   | Code | Message                                                      |
+---------+------+--------------------------------------------------------------+
| Warning | 1292 | Truncated incorrect time value: '2021-04-19 09:35:23 -07:00' |
+---------+------+--------------------------------------------------------------+
1 row in set (0.00 sec)

亚秒 毫秒示例。 (最多可以使用 6 个)

mysql> SELECT NOW(3), CURRENT_TIMESTAMP(3);
+-------------------------+-------------------------+
| NOW(3)                  | CURRENT_TIMESTAMP(3)    |
+-------------------------+-------------------------+
| 2021-04-19 09:49:55.292 | 2021-04-19 09:49:55.292 |
+-------------------------+-------------------------+
1 row in set (0.00 sec)

参考

As of MySQL 8.0.19, you can specify a time zone offset when inserting TIMESTAMP and DATETIME values into a table. The offset is appended to the time part of a datetime literal, with no intravening spaces, and uses the same format used for setting the time_zone system variable, with the following exceptions:

For hour values less than than 10, a leading zero is required.

The value '-00:00' is rejected.

Time zone names such as 'EET' and 'Asia/Shanghai' cannot be used; 'SYSTEM' also cannot be used in this context.

The value inserted must not have a zero for the month part, the day part, or both parts. This is enforced beginning with MySQL 8.0.22, regardless of the server SQL mode setting.

来自https://dev.mysql.com/doc/refman/8.0/en/datetime.html,可能有更多感兴趣的信息。

这也表明 8.0.22 具有:

CAST(col AT TIME ZONE INTERVAL '+00:00' AS DATETIME)

这可能对你有帮助。