MySQL是否应将其时区设置为UTC?


149

/server/191331/should-servers-have-their-timezone-set-to-gmt-utc的后续问题

应该将MySQL时区设置为UTC还是将其设置为与服务器或PHP相同的时区?(如果不是UTC)

优缺点都有什么?


stackoverflow.com/a/1650406/175071分享了使用UTC的充分理由
Timo Huovinen 2014年

UTC不是时区。UTC是标准,GMT是时区。zachholman.com/talk/utc-is-enough-for-everyone-right
agoldev

Answers:


532

只要您为当前时区设置了正确的时间,知道您存储的datetime列的时区,并了解夏令时问题,服务器上的时区似乎就没有关系。

另一方面,如果您可以控制所用服务器的时区,则可以在内部将所有内容设置为UTC,而不必担心时区和DST。

以下是我收集的一些注意事项,这些注意事项涉及如何使用时区作为自己和他人的备忘单形式,这可能会影响该人将为其服务器选择哪个时区以及他/她将如何存储日期和时间。

MySQL时区备忘单

笔记:

  1. 更改时区不会更改存储的日期时间或时间戳,但会从时间戳列中选择其他日期时间
  2. 警告!UTC具有leap秒,它们看起来像“ 2012-06-30 23:59:60”,由于地球自转速度变慢,可以在提前6个月通知的情况下随机添加
  3. GMT混淆了秒,这就是发明UTC的原因。

  4. 警告!由于夏令时,不同的区域时区可能会产生相同的日期时间值

  5. 由于受限制,因此timestamp列仅支持日期1970-01-01 00:00:01到2038-01-19 03:14:07 UTC 。
  6. 在内部,MySQL时间戳列存储为UTC,但是当选择日期时,MySQL会自动将其转换为当前会话时区。

    在时间戳中存储日期时,MySQL将假定该日期在当前会话时区中,并将其转换为UTC进行存储。

  7. MySQL可以在datetime列中存储部分日期,这些日期看起来像“ 2013-00-00 04:00:00”
  8. 如果您将datetime列设置为NULL,则MySQL将存储“ 0000-00-00 00:00:00”,除非您在创建该列时专门将其设置为允许null。
  9. 读这个

选择UTC格式的时间戳列

无论当前MySQL会话位于哪个时区:

SELECT 
CONVERT_TZ(`timestamp_field`, @@session.time_zone, '+00:00') AS `utc_datetime` 
FROM `table_name`

您还可以将服务器或全局或当前会话时区设置为UTC,然后选择时间戳,如下所示:

SELECT `timestamp_field` FROM `table_name`

要选择UTC中的当前日期时间:

SELECT UTC_TIMESTAMP();
SELECT UTC_TIMESTAMP;
SELECT CONVERT_TZ(NOW(), @@session.time_zone, '+00:00');

结果示例: 2015-03-24 17:02:41

在会话时区中选择当前日期时间

SELECT NOW();
SELECT CURRENT_TIMESTAMP;
SELECT CURRENT_TIMESTAMP();

选择服务器启动时设置的时区

SELECT @@system_time_zone;

例如,在莫斯科时间返回“ MSK”或“ +04:00”,这是一个(或曾经是)一个MySQL错误,如果将其设置为数值偏移量,它将不会调整夏令时

获取当前时区

SELECT TIMEDIFF(NOW(), UTC_TIMESTAMP);

如果您的时区为+2:00,它将返回02:00:00。

要获取当前的UNIX时间戳(以秒为单位):

SELECT UNIX_TIMESTAMP(NOW());
SELECT UNIX_TIMESTAMP();

将timestamp列作为UNIX时间戳记

SELECT UNIX_TIMESTAMP(`timestamp`) FROM `table_name`

获取UTC日期时间列作为UNIX时间戳记

SELECT UNIX_TIMESTAMP(CONVERT_TZ(`utc_datetime`, '+00:00', @@session.time_zone)) FROM `table_name`

从正UNIX时间戳整数获取当前时区datetime

SELECT FROM_UNIXTIME(`unix_timestamp_int`) FROM `table_name`

从UNIX时间戳获取UTC日期时间

SELECT CONVERT_TZ(FROM_UNIXTIME(`unix_timestamp_int`), @@session.time_zone, '+00:00') 
FROM `table_name`

从负UNIX时间戳整数获取当前时区datetime

SELECT DATE_ADD('1970-01-01 00:00:00',INTERVAL -957632400 SECOND) 

在MySQL中可以在3个地方设置时区:

注意:时区可以两种格式设置:

  1. 与UTC的偏移量:“ + 00:00”,“ + 10:00”或“ -6:00”
  2. 作为命名时区:“欧洲/赫尔辛基”,“美国/东部”或“ MET”

仅当已创建并填充mysql数据库中的时区信息表时,才能使用命名时区。

在文件“ my.cnf”中

default_time_zone='+00:00'

要么

timezone='UTC'

@@ global.time_zone变量

查看它们设置为什么值

SELECT @@global.time_zone;

要为其设置值,请使用以下任一方法:

SET GLOBAL time_zone = '+8:00';
SET GLOBAL time_zone = 'Europe/Helsinki';
SET @@global.time_zone='+00:00';

@@ session.time_zone变量

SELECT @@session.time_zone;

要设置它,请使用以下任一方法:

SET time_zone = 'Europe/Helsinki';
SET time_zone = "+00:00";
SET @@session.time_zone = "+00:00";

“ @@ global.time_zone变量”和“ @@ session.time_zone变量”都可能返回“ SYSTEM”,这意味着它们使用在“ my.cnf”中设置的时区。

为了使时区名称生效(即使对于默认时区也是如此),您必须设置时区信息表: http : //dev.mysql.com/doc/refman/5.1/en/time-zone-support。 html

注意:您不能执行此操作,因为它将返回NULL:

SELECT 
CONVERT_TZ(`timestamp_field`, TIMEDIFF(NOW(), UTC_TIMESTAMP), '+00:00') AS `utc_datetime` 
FROM `table_name`

设置mysql时区表

为了CONVERT_TZ工作,您需要填充时区表

SELECT * FROM mysql.`time_zone` ;
SELECT * FROM mysql.`time_zone_leap_second` ;
SELECT * FROM mysql.`time_zone_name` ;
SELECT * FROM mysql.`time_zone_transition` ;
SELECT * FROM mysql.`time_zone_transition_type` ;

如果它们为空,则通过运行此命令将其填满

mysql_tzinfo_to_sql /usr/share/zoneinfo | mysql -u root -p mysql

如果此命令给您错误“ 行1的列'缩写'的数据太长 ”错误,则可能是由于在时区缩写的末尾附加了NULL字符引起的

解决办法是运行此

mysql_tzinfo_to_sql /usr/share/zoneinfo | mysql -u root -p mysql
(if the above gives error "data too long for column 'abbreviation' at row 1")
mysql_tzinfo_to_sql /usr/share/zoneinfo > /tmp/zut.sql

echo "SET SESSION SQL_MODE = '';" > /tmp/mysql_tzinfo_to.sql
cat /tmp/zut.sql >> /tmp/mysql_tzinfo_to.sql

mysql --defaults-file=/etc/mysql/my.cnf --user=verifiedscratch -p mysql < /tmp/mysql_tzinfo_to.sql

(确保您的服务器dst规则是最新的zdump -v Europe/Moscow | grep 2011 https://chrisjean.com/updating-daylight-saving-time-on-linux/

查看每个时区的完整DST(夏令时)过渡历史记录

SELECT 
tzn.Name AS tz_name,
tztt.Abbreviation AS tz_abbr,
tztt.Is_DST AS is_dst,
tztt.`Offset` AS `offset`,
DATE_ADD('1970-01-01 00:00:00',INTERVAL tzt.Transition_time SECOND)  AS transition_date
FROM mysql.`time_zone_transition` tzt
INNER JOIN mysql.`time_zone_transition_type` tztt USING(Time_zone_id, Transition_type_id)
INNER JOIN mysql.`time_zone_name` tzn USING(Time_zone_id)
-- WHERE tzn.Name LIKE 'Europe/Moscow' -- Moscow has weird DST changes
ORDER BY tzt.Transition_time ASC

CONVERT_TZ 还会根据上表中的规则和使用日期应用所有必要的DST更改。

注意:
根据docs,您为time_zone设置的值不会更改,例如,如果将其设置为“ +01:00”,则time_zone将被设置为与UTC的偏移量,它不遵循DST,因此它将全年保持不变。

在夏令时期间,只有指定的时区会更改时间。

像这样的缩写CET将始终是冬季时间,CEST将是夏季时间,而+01:00则始终是UTC时间+ 1小时,并且两者都不会随着DST改变。

system时区将被安装的MySQL,其中主机的时区(除非MySQL的失败来确定它)

您可以在此处阅读有关使用DST的更多信息。

相关问题:

资料来源:


因此,如果我将列类型设置为时间戳。我的time_zone是+12:00,我想使用基于utc的日期/时间来更新一列,是否有任何方法可以在更新语句中包含时区,或者我应该使用convert_tz。例如。更新tablemodified=“2016年7月7日8点10分00:00”
bumperbox

2
@bumperbox mysql始终假定您提供的时间戳列日期与mysql服务器位于相同的时区,因此您需要将日期从+12:00时区转换为mysql服务器时区以进行更新。这就是为什么我在mysql服务器上使用UTC并在存储之前将任何日期转换为UTC的原因。
Timo Huovinen

5
我在使用SO的多年中遇到的最好,最有用的答案之一。谢谢。
Mitya

警告!!!在夏令时结束时,每年DST时区中任何本地时间的使用或转换都将导致一个小时小时的错误。这会影响UNIX_TIMESTAMP(NOW());以及您对CONVERT_TZ()其中参数之一为`@@ session.time_zone的所有使用。为了将UTC日期时间可靠地转换为UNIX时间戳,基本上必须首先设置会话time_zone。
Doin

1
@Flimm完全正确,我前一段时间忘了修复它。
Timo Huovinen

3

这是一个工作示例:

jdbc:mysql://localhost:3306/database?useUnicode=yes&characterEncoding=UTF-8&serverTimezone=Europe/Moscow

2

PHP和MySQL具有自己的默认时区配置。您应该在数据库和Web应用程序之间同步时间,否则您可能会遇到一些问题。

阅读本教程:如何同步PHP和MySQL时区


它基本上是两行代码:date_default_timezone_set("America/Los_Angeles");mysql_query("SET time_zone='" . date('P', time()) . "'");非常优雅地工作!
Noumenon 2015年

3
@ Noumenon小心点!今天早上我一直在挠头,因为那正是我在做的事情,现在我的部分时间已经减少了一个小时。我怀疑当涉及DST时,使用命名时区会更准确。如果您使用America / New_York,则MySQL会了解DST,并将适当地存储日期。如果像此处一样将其设置为-04:00,则不会考虑DST计算。
nathanb 2015年

1
请检查mysql是否正确了解DST,DST规则会定期更新,并且相关的mysql表也需要更新(请参见上方答案底部)
Timo Huovinen

1

优点和缺点几乎相同,这取决于您是否要这样做。

请注意,如果MySQL时区与您的系统时间(例如PHP)不同,则比较时间或向用户打印将涉及一些修改。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.