MySQL是否应将其时区设置为UTC? [英] Should MySQL have its timezone set to UTC?

查看:73
本文介绍了MySQL是否应将其时区设置为UTC?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

跟进的问题 https://serverfault.com/questions/191331/should-服务器已将其时区设置为gmt-utc

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

优缺点是什么?

解决方案

只要您为当前时区设置了正确的时间,服务器上的时区似乎并不重要,请知道datetime的时区您存储的列,并且知道夏令时的问题.

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

以下是我收集的一些笔记,这些笔记是我和其他人如何使用时区作弊的一种备忘单,这可能会影响该人将为其服务器选择的时区以及他/她将如何存储日期和时间.

MySQL时区备忘单

注意:

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

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

  5. 由于 MySQL时间戳列 UTC ,但 选择日期时,MySQL会自动将其转换为 当前会话的时区.

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

  6. MySQL可以在datetime列中存储部分日期,这些看起来像 "2013-00-00 04:00:00"
  7. 如果将datetime列设置为MySQL,则MySQL存储"0000-00-00 00:00:00" NULL,除非您专门将列设置为在您允许空值时 创建它.
  8. 阅读

要选择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时间戳整数获取当前时区的日期时间

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时间戳整数获取当前时区日期时间

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

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

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

  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"中设置的时区.

为使时区名称起作用(即使对于默认时区也是如此),您必须设置时区信息表: 数据太长而无法在行中使用缩写"列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 ,您设置的值for time_zone不会更改,例如,如果将其设置为"+01:00",则time_zone将设置为与UTC的偏移量(不遵循DST,因此整年都保持不变).

只有命名的时区会在夏令时更改时间.

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

system时区将是安装mysql的主机的时区(除非mysql无法确定它)

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

相关问题:

来源:

Follow up question of https://serverfault.com/questions/191331/should-servers-have-their-timezone-set-to-gmt-utc

Should the MySQL timezone be set to UTC or should it be set to be the same timezone as the server or PHP is set? (If it is not UTC)

What are the pros and cons?

解决方案

It seems that it does not matter what timezone is on the server as long as you have the time set right for the current timezone, know the timezone of the datetime columns that you store, and are aware of the issues with daylight savings time.

On the other hand if you have control of the timezones of the servers you work with then you can have everything set to UTC internally and never worry about timezones and DST.

Here are some notes I collected of how to work with timezones as a form of cheatsheet for myself and others which might influence what timezone the person will choose for his/her server and how he/she will store date and time.

MySQL Timezone Cheatsheet

Notes:

  1. Changing the timezone will not change the stored datetime or timestamp, but it will select a different datetime from timestamp columns
  2. Warning! UTC has leap seconds, these look like '2012-06-30 23:59:60' and can be added randomly, with 6 months prior notice, due to the slowing of the earths rotation
  3. GMT confuses seconds, which is why UTC was invented.

  4. Warning! different regional timezones might produce the same datetime value due to daylight savings time

  5. The timestamp column only supports dates 1970-01-01 00:00:01 to 2038-01-19 03:14:07 UTC, due to a limitation.
  6. Internally a MySQL timestamp column is stored as UTC but when selecting a date MySQL will automatically convert it to the current session timezone.

    When storing a date in a timestamp, MySQL will assume that the date is in the current session timezone and convert it to UTC for storage.

  7. MySQL can store partial dates in datetime columns, these look like "2013-00-00 04:00:00"
  8. MySQL stores "0000-00-00 00:00:00" if you set a datetime column as NULL, unless you specifically set the column to allow null when you create it.
  9. Read this

To select a timestamp column in UTC format

no matter what timezone the current MySQL session is in:

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

You can also set the sever or global or current session timezone to UTC and then select the timestamp like so:

SELECT `timestamp_field` FROM `table_name`

To select the current datetime in UTC:

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

Example result: 2015-03-24 17:02:41

To select the current datetime in the session timezone

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

To select the timezone that was set when the server launched

SELECT @@system_time_zone;

Returns "MSK" or "+04:00" for Moscow time for example, there is (or was) a MySQL bug where if set to a numerical offset it would not adjust the Daylight savings time

To get the current timezone

SELECT TIMEDIFF(NOW(), UTC_TIMESTAMP);

It will return 02:00:00 if your timezone is +2:00.

To get the current UNIX timestamp (in seconds):

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

To get the timestamp column as a UNIX timestamp

SELECT UNIX_TIMESTAMP(`timestamp`) FROM `table_name`

To get a UTC datetime column as a UNIX timestamp

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

Get a current timezone datetime from a positive UNIX timestamp integer

SELECT FROM_UNIXTIME(`unix_timestamp_int`) FROM `table_name`

Get a UTC datetime from a UNIX timestamp

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

Get a current timezone datetime from a negative UNIX timestamp integer

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

There are 3 places where the timezone might be set in MySQL:

Note: A timezone can be set in 2 formats:

  1. an offset from UTC: '+00:00', '+10:00' or '-6:00'
  2. as a named time zone: 'Europe/Helsinki', 'US/Eastern', or 'MET'

Named time zones can be used only if the time zone information tables in the mysql database have been created and populated.

in the file "my.cnf"

default_time_zone='+00:00'

or

timezone='UTC'

@@global.time_zone variable

To see what value they are set to

SELECT @@global.time_zone;

To set a value for it use either one:

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

@@session.time_zone variable

SELECT @@session.time_zone;

To set it use either one:

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

both "@@global.time_zone variable" and "@@session.time_zone variable" might return "SYSTEM" which means that they use the timezone set in "my.cnf".

For timezone names to work (even for default-time-zone) you must setup your timezone information tables need to be populated: http://dev.mysql.com/doc/refman/5.1/en/time-zone-support.html

Note: you can not do this as it will return NULL:

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

Setup mysql timezone tables

For CONVERT_TZ to work, you need the timezone tables to be populated

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` ;

If they are empty, then fill them up by running this command

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

if this command gives you the error "data too long for column 'abbreviation' at row 1", then it might be caused by a NULL character being appended at the end of the timezone abbreviation

the fix being to run this

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

(make sure your servers dst rules are up to date zdump -v Europe/Moscow | grep 2011 https://chrisjean.com/updating-daylight-saving-time-on-linux/)

See the full DST (Daylight Saving Time) transition history for every timezone

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 also applies any necessary DST changes based on the rules in the above tables and the date that you use.

Note:
According to the docs, the value you set for time_zone does not change, if you set it as "+01:00" for example, then the time_zone will be set as an offset from UTC, which does not follow DST, so it will stay the same all year round.

Only the named timezones will change time during daylight savings time.

Abbreviations like CET will always be a winter time and CEST will be summer time while +01:00 will always be UTC time + 1 hour and both won't change with DST.

The system timezone will be the timezone of the host machine where mysql is installed (unless mysql fails to determine it)

You can read more about working with DST here

related questions:

Sources:

这篇关于MySQL是否应将其时区设置为UTC?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆