Mysql
 sql >> Base de Dados >  >> RDS >> Mysql

O MySQL deve ter seu fuso horário definido como UTC?


Parece que não importa qual fuso horário está no servidor, desde que você tenha o horário definido para o fuso horário atual, conheça o fuso horário das colunas de data e hora que você armazena e esteja ciente dos problemas com o horário de verão.

Por outro lado, se você tiver controle dos fusos horários dos servidores com os quais trabalha, poderá configurar tudo para UTC internamente e nunca se preocupar com fusos horários e DST.

Aqui estão algumas notas que coletei sobre como trabalhar com fusos horários como uma forma de cheatsheet para mim e para outras pessoas que podem influenciar qual fuso horário a pessoa escolherá para seu servidor e como ela armazenará data e hora.

Folha de dicas de fuso horário do MySQL


Notas:

  1. Alterar o fuso horário não alterará a data/hora ou carimbo de data/hora armazenados , mas selecionará uma data e hora diferente das colunas de carimbo de data/hora

  2. Aviso! UTC tem segundos bissextos, estes se parecem com '2012-06-30 23:59:60' e podem ser adicionados aleatoriamente, com 6 meses de antecedência, devido à desaceleração da rotação da Terra

  3. O GMT confunde os segundos, e é por isso que o UTC foi inventado.

  4. Aviso! diferentes fusos horários regionais podem produzir o mesmo valor de data e hora devido ao horário de verão

  5. A coluna de carimbo de data/hora é compatível apenas com datas de 1970-01-01 00:00:01 a 2038-01-19 03:14:07 UTC, devido a uma limitação .

  6. Internamente, uma coluna de carimbo de data/hora do MySQL é armazenado como UTC mas ao selecionar uma data o MySQL irá convertê-la automaticamente para o fuso horário da sessão atual.

    Ao armazenar uma data em um carimbo de data/hora, o MySQL assumirá que a data está no fuso horário da sessão atual e a converterá para armazenamento UTC.

  7. O MySQL pode armazenar datas parciais em colunas de data e hora, como "2013-00-00 04:00:00"

  8. O MySQL armazena "0000-00-00 00:00:00" se você definir uma coluna de data e hora como NULL, a menos que você defina especificamente a coluna para permitir null ao criá-la.

  9. Leia isto

Para selecionar uma coluna de carimbo de data/hora no formato UTC


não importa em que fuso horário a sessão atual do MySQL esteja:
SELECT 
CONVERT_TZ(`timestamp_field`, @@session.time_zone, '+00:00') AS `utc_datetime` 
FROM `table_name`

Você também pode definir o fuso horário do servidor ou da sessão global ou atual como UTC e, em seguida, selecionar o carimbo de data/hora da seguinte forma:
SELECT `timestamp_field` FROM `table_name`

Para selecionar a data e hora atual em UTC:

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

Exemplo de resultado:2015-03-24 17:02:41

Para selecionar a data e hora atual no fuso horário da sessão

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

Para selecionar o fuso horário que foi definido quando o servidor foi iniciado

SELECT @@system_time_zone;

Retorna "MSK" ou "+04:00" para o horário de Moscou, por exemplo, há (ou houve) um bug do MySQL onde, se definido para um deslocamento numérico, não ajustaria o horário de verão

Para obter o fuso horário atual

SELECT TIMEDIFF(NOW(), UTC_TIMESTAMP);

Ele retornará 02:00:00 se seu fuso horário for +2:00.

Para obter o timestamp atual do UNIX (em segundos):

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

Para obter a coluna timestamp como um timestamp UNIX

SELECT UNIX_TIMESTAMP(`timestamp`) FROM `table_name`

Para obter uma coluna de data e hora UTC como um carimbo de data/hora UNIX

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

Obter uma data e hora do fuso horário atual de um número de carimbo de data/hora positivo do UNIX

SELECT FROM_UNIXTIME(`unix_timestamp_int`) FROM `table_name`

Obter uma data e hora UTC de um carimbo de data/hora UNIX

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

Obter uma data e hora do fuso horário atual de um inteiro de carimbo de data/hora UNIX negativo

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

Existem 3 lugares onde o fuso horário pode ser definido no MySQL:


Nota:Um fuso horário pode ser definido em 2 formatos:
  1. um deslocamento do UTC:'+00:00', '+10:00' ou '-6:00'
  2. como um fuso horário nomeado:'Europe/Helsinki', 'US/Eastern' ou 'MET'

Os fusos horários nomeados podem ser usados ​​somente se as tabelas de informações de fuso horário no banco de dados mysql tiverem sido criadas e preenchidas.

no arquivo "my.cnf"

default_time_zone='+00:00'

ou
timezone='UTC'

@@global.time_zone variável


Para ver qual valor eles estão definidos para
SELECT @@global.time_zone;

Para definir um valor para ele, use qualquer um:
SET GLOBAL time_zone = '+8:00';
SET GLOBAL time_zone = 'Europe/Helsinki';
SET @@global.time_zone='+00:00';

@@session.time_zone variável

SELECT @@session.time_zone;

Para configurá-lo, use qualquer um:
SET time_zone = 'Europe/Helsinki';
SET time_zone = "+00:00";
SET @@session.time_zone = "+00:00";

tanto "@@global.time_zone variable" quanto "@@session.time_zone variable" podem retornar "SYSTEM", o que significa que eles usam o fuso horário definido em "my.cnf".

Para que os nomes de fuso horário funcionem (mesmo para o fuso horário padrão), você deve configurar suas tabelas de informações de fuso horário que precisam ser preenchidas: http://dev.mysql.com/doc /refman/5.1/en/time-zone-support.html

Nota:você não pode fazer isso, pois retornará NULL:
SELECT 
CONVERT_TZ(`timestamp_field`, TIMEDIFF(NOW(), UTC_TIMESTAMP), '+00:00') AS `utc_datetime` 
FROM `table_name`

Configurar tabelas de fuso horário mysql


Para CONVERT_TZ para funcionar, você precisa que as tabelas de fuso horário sejam preenchidas
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` ;

Se eles estiverem vazios, preencha-os executando este comando
mysql_tzinfo_to_sql /usr/share/zoneinfo | mysql -u root -p mysql

se este comando lhe der o erro "dados muito longos para a coluna 'abbreviation' na linha 1 ", então pode ser causado por um caractere NULL sendo anexado no final da abreviação do fuso horário

a correção é executar isso
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

(certifique-se de que as regras dst de seus servidores estejam atualizadas zdump -v Europe/Moscow | grep 2011 https://chrisjean.com/updating-daylight-saving-time- on-linux/ )

Veja o histórico completo de transição do horário de verão (DST) para cada fuso horário

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 também aplica quaisquer alterações de horário de verão necessárias com base nas regras nas tabelas acima e na data que você usa.

Observação:
De acordo com os documentos , o valor que você definiu para time_zone não muda, se você definir como "+01:00", por exemplo, o time_zone será definido como um deslocamento do UTC, que não segue o horário de verão, portanto, permanecerá o mesmo todos durante todo o ano.

Apenas os fusos horários nomeados mudará a hora durante o horário de verão.

Abreviações como CET sempre será um horário de inverno e CEST será o horário de verão enquanto +01:00 sempre será UTC hora + 1 hora e ambos não mudarão com o horário de verão.

O system timezone será o fuso horário da máquina host onde o mysql está instalado (a menos que o mysql falhe em determiná-lo)

Você pode ler mais sobre como trabalhar com DST aqui

Quando não usar UTC pelo lendário Jon Skeet:https://codeblog.jonskeet.uk/2019/03/27/storing-utc-is-not-a-silver-bullet/ (Por exemplo, um evento agendado no futuro que representa uma hora, não um instante no tempo)

Perguntas relacionadas:

Origens: