Uma consulta das vendas do mês pode deixar de fora o último dia, um horário pode aparecer com três horas de diferença entre dois sistemas, e uma data zerada pode travar a leitura de um relatório. As datas no banco seguem regras próprias de tipo, de formato e de fuso horário, e conhecer essas regras evita conclusões erradas sobre dados ausentes.
Os tipos de data e hora
- DATE: guarda apenas a data, como 2026-10-07.
- DATETIME: guarda a data e o horário, como 2026-10-07 14:35:20, exatamente como foram informados, sem nenhuma conversão de fuso.
- TIMESTAMP: também guarda a data e o horário, mas converte o valor para o horário universal, chamado UTC, na gravação e de volta para o fuso da conexão na leitura. Esse tipo aceita apenas datas entre 1970 e janeiro de 2038.
- TIME: guarda um horário ou uma duração, como 14:35:20.
No cenário, a coluna data_venda da tabela vendas é do tipo DATETIME.
O formato das datas no SQL
O MySQL escreve e lê as datas com o ano primeiro, no formato ano, mês e dia, e o valor vai entre aspas simples, como em '2026-10-07' ou '2026-10-07 14:35:20'. Uma data no formato brasileiro, com o dia primeiro, não é entendida como data, e a comparação falha ou encontra outra data. Duas funções fazem a conversão entre os formatos:
DATE_FORMAT(data_venda, '%d/%m/%Y %H:%i'): mostra a data no formato brasileiro, como 07/10/2026 14:35;STR_TO_DATE('07/10/2026', '%d/%m/%Y'): transforma um texto no formato brasileiro em uma data que o MySQL entende.
Filtrar por dia e por período
Em uma coluna DATETIME, uma data sem horário equivale à meia-noite do início daquele dia. Por isso, a condição a seguir não traz as vendas feitas depois da meia-noite do dia 31:
WHERE data_venda BETWEEN '2026-10-01' AND '2026-10-31': inclui o dia 31 apenas até o instante 00:00:00.
A forma segura usa o início do período seguinte como limite, sem incluí-lo:
WHERE data_venda >= '2026-10-01' AND data_venda < '2026-11-01': traz todas as vendas de outubro, inclusive as do dia 31 inteiro.
A função DATE, aplicada à coluna, também filtra um dia inteiro, mas tem um custo:
WHERE DATE(data_venda) = '2026-10-07': traz as vendas do dia 7, mas obriga o MySQL a calcular a função em cada linha e impede o uso eficiente do índice da coluna.
Em tabelas grandes, o intervalo com maior ou igual e menor que é a forma mais rápida.
O fuso horário
O servidor MySQL tem um fuso horário configurado, e cada conexão pode usar o fuso do servidor ou outro. O valor SYSTEM indica que o MySQL usa o fuso do sistema operacional. Um comando mostra a data, a hora e os fusos em uso:
SELECT NOW(), @@global.time_zone, @@session.time_zone;
A função NOW mostra o momento atual segundo o relógio do servidor. Se o relógio do servidor estiver errado, as vendas são gravadas com datas e horários errados, mesmo que o relógio das estações esteja certo.
Uma diferença exata de três horas entre dois sistemas costuma indicar que um deles trabalha em UTC, e o outro no horário de Brasília, que fica três horas atrás do UTC. Esse caso é comum em integrações com serviços na Internet. Nas colunas TIMESTAMP, duas conexões com fusos diferentes enxergam horários diferentes para a mesma linha, porque o MySQL converte o valor para o fuso de cada conexão.
O Brasil deixou de adotar o horário de verão em 2019. Em dados mais antigos, os horários gravados durante os períodos de horário de verão podem estar deslocados em uma hora quando comparados com outras fontes.
Datas inválidas e datas zeradas
Instalações antigas podem ter datas zeradas, como 0000-00-00, gravadas quando um valor não era informado. Alguns programas e bibliotecas falham ao ler essas datas. A partir do MySQL 5.7, o modo padrão recusa a gravação de datas zeradas e de datas inexistentes, como 30 de fevereiro, com o erro 1292, de valor de data incorreto. Nas tabelas MyISAM, essa recusa só é garantida na primeira linha de cada comando. Nas linhas seguintes de um comando que grava várias linhas, uma data inválida pode ser gravada como 0000-00-00, com um aviso, porque as linhas anteriores já foram gravadas e não podem ser desfeitas.
Contas com datas
O MySQL faz contas com datas por meio de funções:
WHERE data_venda >= NOW() - INTERVAL 7 DAY: traz as vendas dos últimos sete dias;DATEDIFF('2026-10-07', '2026-10-01'): mostra a diferença em dias, que nesse exemplo é 6;TIMESTAMPDIFF(MINUTE, inicio, fim): mostra a diferença em minutos entre duas colunas de data e horário.
No suporte
Antes de comparar horários entre o banco, os registros do sistema e outro servidor, convém confirmar o tipo da coluna e o fuso de cada origem. Uma diferença exata de três horas costuma ter origem no fuso, e não em um erro nos dados. Um período que parece incompleto pede a conferência do limite final da condição.
Para guardar
- DATE guarda a data, DATETIME guarda a data e o horário sem conversão, e TIMESTAMP converte o horário pelo fuso da conexão.
- O MySQL usa o formato ano, mês e dia, e as funções DATE_FORMAT e STR_TO_DATE convertem os formatos.
- Em DATETIME, uma data sem horário vale a meia-noite do início do dia.
- O intervalo com maior ou igual e menor que traz períodos completos e usa o índice.
- Uma diferença exata de três horas costuma indicar UTC de um lado e horário de Brasília do outro.
A consulta das vendas de outubro, com BETWEEN '2026-10-01' AND '2026-10-31', não traz as vendas do dia 31. Por quê?
A coluna data_venda é do tipo DATETIME, e a data '2026-10-31' sem horário equivale à meia-noite do início do dia 31. As vendas feitas depois desse instante ficam de fora. A condição data_venda >= '2026-10-01' AND data_venda < '2026-11-01' inclui o dia 31 inteiro.
Uma integração mostra as vendas com três horas a mais do que o horário gravado no banco da loja. O que verificar?
O fuso horário de cada lado. Uma diferença exata de três horas costuma indicar que uma das partes trabalha em UTC e a outra no horário de Brasília. A conferência envolve o tipo da coluna, o fuso da conexão com o banco e o formato de data que a integração espera.