sql >> Base de Datos >  >> RDS >> Mysql

¿Debe MySQL tener su zona horaria establecida en UTC?

Parece que no importa qué zona horaria esté en el servidor, siempre que tenga la hora establecida correctamente para la zona horaria actual, conozca la zona horaria de las columnas de fecha y hora que almacena y esté al tanto de los problemas con el horario de verano.

Por otro lado, si tiene el control de las zonas horarias de los servidores con los que trabaja, puede tener todo configurado en UTC internamente y nunca preocuparse por las zonas horarias y el horario de verano.

Aquí hay algunas notas que recopilé sobre cómo trabajar con zonas horarias como una forma de hoja de trucos para mí y para otros que podrían influir en qué zona horaria elegirá la persona para su servidor y cómo almacenará la fecha y la hora.

Hoja de trucos de zona horaria de MySQL

Notas:

  1. Cambiar la zona horaria no cambiará la fecha y la hora almacenadas , pero seleccionará una fecha y hora diferente de las columnas de marca de tiempo

  2. ¡Advertencia! UTC tiene segundos bisiestos, estos parecen '2012-06-30 23:59:60' y se pueden agregar al azar, con 6 meses de anticipación, debido a la desaceleración de la rotación de la tierra

  3. GMT confunde segundos, razón por la cual se inventó UTC.

  4. ¡Advertencia! diferentes zonas horarias regionales pueden producir el mismo valor de fecha y hora debido al horario de verano

  5. La columna de marca de tiempo solo admite fechas 1970-01-01 00:00:01 a 2038-01-19 03:14:07 UTC, debido a una limitación .

  6. Internamente, una columna de marca de tiempo de MySQL se almacena como UTC pero al seleccionar una fecha, MySQL la convertirá automáticamente a la zona horaria de la sesión actual.

    Al almacenar una fecha en una marca de tiempo, MySQL asumirá que la fecha está en la zona horaria de la sesión actual y la convertirá a UTC para el almacenamiento.

  7. MySQL puede almacenar fechas parciales en columnas de fecha y hora, estas parecen "2013-00-00 04:00:00"

  8. MySQL almacena "0000-00-00 00:00:00" si configura una columna de fecha y hora como NULL, a menos que configure específicamente la columna para permitir nulo cuando la cree.

  9. Lee esto

Para seleccionar una columna de marca de tiempo en formato UTC

no importa en qué zona horaria se encuentre la sesión actual de MySQL:

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

También puede configurar la zona horaria del servidor, global o de la sesión actual en UTC y luego seleccionar la marca de tiempo de la siguiente manera:

SELECT `timestamp_field` FROM `table_name`

Para seleccionar la fecha y hora actual en UTC:

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

Resultado de ejemplo:2015-03-24 17:02:41

Para seleccionar la fecha y hora actual en la zona horaria de la sesión

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

Para seleccionar la zona horaria que se configuró cuando se lanzó el servidor

SELECT @@system_time_zone;

Devuelve "MSK" o "+04:00" para la hora de Moscú, por ejemplo, hay (o había) un error de MySQL en el que, si se establece en un desplazamiento numérico, no se ajustaría el horario de verano

Para obtener la zona horaria actual

SELECT TIMEDIFF(NOW(), UTC_TIMESTAMP);

Volverá a las 02:00:00 si su zona horaria es +2:00.

Para obtener la marca de tiempo UNIX actual (en segundos):

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

Para obtener la columna de marca de tiempo como una marca de tiempo UNIX

SELECT UNIX_TIMESTAMP(`timestamp`) FROM `table_name`

Para obtener una columna de fecha y hora UTC como una marca de tiempo UNIX

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

Obtener una fecha y hora de la zona horaria actual a partir de un entero de marca de tiempo UNIX positivo

SELECT FROM_UNIXTIME(`unix_timestamp_int`) FROM `table_name`

Obtener una fecha y hora UTC de una marca de tiempo UNIX

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

Obtener una fecha y hora de la zona horaria actual a partir de un entero de marca de tiempo UNIX negativo

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

Hay 3 lugares donde se puede establecer la zona horaria en MySQL:

Nota:una zona horaria se puede establecer en 2 formatos:

  1. un desplazamiento de UTC:'+00:00', '+10:00' o '-6:00'
  2. como una zona horaria con nombre:'Europa/Helsinki', 'EE. UU./Este' o 'MET'

Las zonas horarias con nombre solo se pueden usar si las tablas de información de zonas horarias en la base de datos mysql se han creado y completado.

en el archivo "mi.cnf"

default_time_zone='+00:00'

o

timezone='UTC'

@@variable global.time_zone

Para ver en qué valor están configurados

SELECT @@global.time_zone;

Para establecer un valor, use cualquiera de los dos:

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

@@sesión.variable de zona horaria

SELECT @@session.time_zone;

Para configurarlo, use cualquiera de los dos:

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

tanto "@@global.time_zone variable" como "@@session.time_zone variable" pueden devolver "SYSTEM", lo que significa que usan la zona horaria configurada en "my.cnf".

Para que los nombres de las zonas horarias funcionen (incluso para la zona horaria predeterminada), debe configurar las tablas de información de la zona horaria que deben completarse: http://dev.mysql.com/doc /refman/5.1/en/time-zone-support.html

Nota:no puede hacer esto ya que devolverá NULL:

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

Configurar tablas de zona horaria mysql

Para CONVERT_TZ para trabajar, necesita que las tablas de zonas horarias estén completas

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

Si están vacíos, llénelos ejecutando este comando

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

si este comando le da el error "datos demasiado largos para la columna 'abreviatura' en la fila 1 ", entonces podría deberse a que se agrega un carácter NULL al final de la abreviatura de la zona horaria

la solución es ejecutar esto

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

(asegúrese de que las reglas de horario de verano de sus servidores estén actualizadas zdump -v Europe/Moscow | grep 2011 https://chrisjean.com/actualizando-el-horario-de-ahorro- en Linux/ )

Vea el historial de transición DST (horario de verano) completo para cada zona horaria

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 también aplica cualquier cambio de horario de verano necesario según las reglas de las tablas anteriores y la fecha que usa.

Nota:
Según los docs , el valor que establece para time_zone no cambia, si lo establece como "+01:00", por ejemplo, time_zone se establecerá como un desplazamiento de UTC, que no sigue el horario de verano, por lo que permanecerá igual todo el tiempo. todo el año.

Solo las zonas horarias nombradas cambiará la hora durante el horario de verano.

Abreviaturas como CET siempre será un horario de invierno y CEST será horario de verano mientras que +01:00 siempre será UTC tiempo + 1 hora y ambos no cambiarán con DST.

El system zona horaria será la zona horaria de la máquina host donde está instalado mysql (a menos que mysql no pueda determinarlo)

Puede leer más sobre cómo trabajar con DST aquí

Cuándo no usar UTC por el legendario Jon Skeet:https://codeblog.jonskeet.uk/2019/03/27/almacenar-utc-no-es-una-bala-de-plata/ (Por ejemplo, un evento programado en el futuro que representa una hora, no un instante en el tiempo)

preguntas relacionadas:

Fuentes: