- 1 1. O SQL mais curto para obter a data/hora atual no MySQL
- 1.1 1.1 Obter a data/hora atual (básico)
- 1.2 1.2 Obter apenas a data de hoje
- 1.3 1.3 Obter apenas o tempo atual
- 1.4 1.4 Obter o tempo atual em UTC (importante)
- 1.5 1.5 Obter milissegundos / microssegundos
- 1.6 1.6 Melhor função por caso de uso (comece aqui se não tiver certeza)
- 1.7 Pontos principais que as pessoas frequentemente perdem
- 2 2. Diferenças entre NOW() / CURRENT_TIMESTAMP / SYSDATE()
- 3 3. Alterar o formato de exibição da data/hora atual
- 4 4. Cálculos de datetime usando o tempo atual
- 4.1 4.1 Adicionar/subtrair com INTERVAL
- 4.2 4.2 Obter dados das últimas 24 horas (padrão mais comum)
- 4.3 4.3 Obter diferenças de dias com DATEDIFF()
- 4.4 4.4 Usar TIMESTAMPDIFF() para horas/minutos/segundos
- 4.5 4.5 Obter início/fim do mês (armadilha comum no mundo real)
- 4.6 Resumo de erros comuns
- 4.7 Principais aprendizados desta seção
- 5 5. Para consultas de intervalo, isso é mais seguro que BETWEEN
- 5.1 5.1 Noções básicas de BETWEEN e a armadilha
- 5.2 5.2 Padrão mais seguro (recomendado)
- 5.3 5.3 A maneira correta de obter os dados de hoje
- 5.4 5.4 Padrões seguros para os últimos 7 / últimos 30 dias
- 5.5 5.5 Regra chave para manter índices eficazes
- 5.6 Resumo de erros comuns
- 5.7 Principais conclusões desta seção
- 6 6. DEFAULT CURRENT_TIMESTAMP e ON UPDATE (noções básicas de design de tabelas)
- 6.1 6.1 Definir automaticamente created_at (DEFAULT CURRENT_TIMESTAMP)
- 6.2 6.2 Atualização automática de updated_at (ON UPDATE)
- 6.3 6.3 DATETIME vs TIMESTAMP (importante)
- 6.4 6.4 CURRENT_TIMESTAMP também pode ser usado com DATETIME
- 6.5 6.5 Se você quiser usar NOW(): uma alternativa (trigger)
- 6.6 Erros comuns de design
- 6.7 Principais lições desta seção
- 7 7. Design de fuso horário (armazenar em UTC, exibir no horário local)
- 7.1 7.1 Verificar o fuso horário atual
- 7.2 7.2 Alterar o fuso horário por sessão
- 7.3 7.3 Por que armazenar em UTC (princípio do mundo real)
- 7.4 7.4 Converter fusos horários com CONVERT_TZ()
- 7.5 7.5 Por que CONVERT_TZ() retorna NULL
- 7.6 7.6 Alterar o fuso horário em todo o servidor
- 7.7 Erros comuns
- 7.8 Principais lições desta seção
- 8 8. Exemplos práticos que você pode usar como estão
- 8.1 8.1 Inserir automaticamente o horário atual em logs
- 8.2 8.2 Atualizar o horário do último login
- 8.3 8.3 Fixar um tempo de referência em jobs em lote
- 8.4 8.4 Agregação para hoje / ontem / últimos 7 dias
- 8.5 8.5 Verificações de expiração (sessões/tokens)
- 8.6 8.6 Obter linhas que expiram dentro de N horas
- 8.7 O que você deve sempre ter em mente
- 8.8 Principais conclusões desta seção
- 9 9. Perguntas Frequentes (FAQ)
- 9.1 9.1 Qual é a diferença entre NOW() e CURRENT_TIMESTAMP?
- 9.2 9.2 Você deve usar SYSDATE()?
- 9.3 9.3 Por que o horário está deslocado?
- 9.4 9.4 CONVERT_TZ() returns NULL
- 9.5 9.5 Range shifts with BETWEEN
- 9.6 9.6 How do you choose between DATETIME and TIMESTAMP?
- 9.7 9.7 Microseconds aren’t being stored
- 9.8 Key takeaways from this section
- 10 10. Summary
1. O SQL mais curto para obter a data/hora atual no MySQL
Se você quiser obter a data/hora atual no MySQL, as primeiras funções a lembrar são NOW() e CURRENT_TIMESTAMP. Abaixo estão os exemplos SQL mais curtos por caso de uso.
1.1 Obter a data/hora atual (básico)
SELECT NOW();
ou
SELECT CURRENT_TIMESTAMP;
- Ambas retornam a data/hora atual (YYYY-MM-DD HH:MM:SS) .
- Dentro da mesma consulta, o tempo é fixado no “início da consulta”.
Casos de uso
- Registro de logs
- Obtenção de um carimbo de tempo de criação de registro
- Obtenção de um tempo de referência
Erro comum
- O fuso horário do app e o fuso horário do BD diferem e “o tempo muda.” → Verifique com
SELECT @@session.time_zone;
1.2 Obter apenas a data de hoje
SELECT CURDATE();
- Formato de retorno:
YYYY-MM-DD - Tipo é DATE (apenas data, não datetime)
Casos de uso
- Busca por “dados de hoje”
- Agregação diária
Notas
- Diferente de
NOW(), não inclui tempo. - Se você precisar de tempo para consultas de intervalo, use
NOW().
1.3 Obter apenas o tempo atual
SELECT CURTIME();
- Formato de retorno:
HH:MM:SS - Tipo é TIME (apenas tempo)
Casos de uso
- Exibição do tempo de execução de lote
- Impressão apenas da porção de tempo em logs
Armadilha comum
- Como não inclui uma data, você não pode usá-lo para comparações de datetime.
1.4 Obter o tempo atual em UTC (importante)
SELECT UTC_TIMESTAMP();
- Retorna UTC independentemente do fuso horário do servidor.
- Recomendado para serviços globais.
Política base em projetos reais
- Armazene em UTC
- Converta para tempo local ao exibir
Notas
- Se o app já converte para UTC, cuidado com conversão dupla.
1.5 Obter milissegundos / microssegundos
SELECT NOW(3); -- milliseconds (3 digits after the decimal point)
SELECT NOW(6); -- microseconds (6 digits after the decimal point)
- Disponível no MySQL 5.6.4 e posterior.
- Usado para logs de alta precisão e auditoria de transações.
Conceito equivocado comum
NOW()sozinho não pode retornar segundos fracionários.- Sua coluna também deve especificar precisão, ex.:
DATETIME(6).
1.6 Melhor função por caso de uso (comece aqui se não tiver certeza)
| Use case | Recommended function |
|---|---|
| General current datetime | NOW() |
| Table default value | CURRENT_TIMESTAMP |
| Date only | CURDATE() |
| Time only | CURTIME() |
| Unified UTC management | UTC_TIMESTAMP() |
| High-precision logs | NOW(6) |
Pontos principais que as pessoas frequentemente perdem
NOW()eCURRENT_TIMESTAMPsão efetivamente equivalentes (mesmo valor)- Dentro da mesma consulta, o tempo é fixado
- O valor exibido muda dependendo das configurações de fuso horário
- Para microssegundos, a definição da sua coluna deve especificar precisão
2. Diferenças entre NOW() / CURRENT_TIMESTAMP / SYSDATE()
Existem várias funções para obter o tempo atual, mas a parte mais confusa é a diferença entre NOW(), CURRENT_TIMESTAMP e SYSDATE().
Se você não entender isso corretamente, pode obter comportamento inesperado em logs e processamento de transações.
2.1 NOW() e CURRENT_TIMESTAMP são efetivamente equivalentes
SELECT NOW(), CURRENT_TIMESTAMP;
- Ambas retornam o datetime atual (um valor DATETIME) .
- Dentro da mesma consulta, o tempo é fixado no “início da consulta.”
CURRENT_TIMESTAMPtambém pode ser usado com sintaxe de chamada de função:SELECT CURRENT_TIMESTAMP();
Como escolher em projetos reais
| Use case | Recommended |
|---|---|
| Simple retrieval | NOW() |
| Table DEFAULT / ON UPDATE | CURRENT_TIMESTAMP |
Pontos importantes
- O significado do valor recuperado é o mesmo.
- A principal diferença é a sintaxe/uso (ex.: permitido em DEFAULT).
- Não é uma diferença de tipo (fácil de entender errado).
2.2 SYSDATE() retorna o tempo no “tempo de avaliação”
SYSDATE() parece similar a NOW(), mas o momento em que o valor é fixado é diferente.
SELECT NOW(), SLEEP(2), NOW();
Resultado (exemplo):
2025-02-23 14:00:00
2025-02-23 14:00:00
SELECT SYSDATE(), SLEEP(2), SYSDATE();
Resultado (exemplo):
2025-02-23 14:00:00
2025-02-23 14:00:02
A diferença essencial
| Function | When the time is fixed |
|---|---|
NOW() | Query start time |
SYSDATE() | Evaluation time |
Em outras palavras, SYSDATE() pode mudar dentro da mesma consulta à medida que o tempo passa.
2.3 Notas para transações e replicação
Porque NOW() é fixo no início da consulta, é
mais seguro quando você precisa de um tempo de referência consistente dentro de uma transação.
Por outro lado, porque SYSDATE() depende do momento de execução, pode afetar a reprodutibilidade em:
- Replicação
- Jobs em lote
- Processamento em massa de logs
Regra geral
- Quer um tempo de referência fixo →
NOW() - Precisa do instante exato toda vez →
SYSDATE()(uso limitado)
2.4 Nota: CURRENT_DATE / CURRENT_TIME / LOCALTIME
O MySQL também suporta:
SELECT CURRENT_DATE;
SELECT CURRENT_TIME;
SELECT LOCALTIME;
CURRENT_DATE→ mesmo queCURDATE()CURRENT_TIME→ mesmo queCURTIME()LOCALTIME→ mesmo queNOW()
Confusão comum
- Essas são principalmente “diferenças cosméticas”; há pouca diferença funcional.
- Por segurança, priorize a legibilidade e padronize dentro do projeto.
Principais lições desta seção
NOW()eCURRENT_TIMESTAMPsignificam essencialmente a mesma coisa.SYSDATE()se comporta de forma diferente porque é baseado no tempo de avaliação.- Para tempos de referência fixos, use
NOW()como padrão. - Use
CURRENT_TIMESTAMPpara DEFAULT e ON UPDATE.
3. Alterar o formato de exibição da data/hora atual
O tempo atual obtido com NOW() é exibido por padrão como YYYY-MM-DD HH:MM:SS. No trabalho real, você frequentemente precisará de coisas como:
- Mostrar apenas a data
- Usar
YYYY/MM/DD - Usar um formato localizado (ex.: 23 Fev, 2025)
- Mostrar milissegundos
Para isso, use DATE_FORMAT() (converte um datetime para um formato de string arbitrário).
3.1 Sintaxe básica de DATE_FORMAT()
DATE_FORMAT(datetime, 'format_string')
Exemplo: Converter o tempo atual para YYYY/MM/DD HH:MM
SELECT DATE_FORMAT(NOW(), '%Y/%m/%d %H:%i');
Exemplo de saída:
2025/02/23 14:35
Especificadores de formato comuns
| Specifier | Meaning | Example |
|---|---|---|
%Y | 4-digit year | 2025 |
%m | 2-digit month | 02 |
%d | 2-digit day | 23 |
%H | Hour (24-hour) | 14 |
%i | Minutes | 35 |
%s | Seconds | 50 |
%f | Microseconds | 123456 |
Notas
- Alguns especificadores diferem entre maiúscula/minúscula.
%hé hora de 12 horas,%Hé hora de 24 horas.
3.2 Exemplos de formatos comuns (frequentes no trabalho real)
1. Separado por barras
SELECT DATE_FORMAT(NOW(), '%Y/%m/%d');
2. Localizado (Inglês)
SELECT DATE_FORMAT(NOW(), '%b %d, %Y');
3. Sem segundos
SELECT DATE_FORMAT(NOW(), '%Y-%m-%d %H:%i');
Armadilha comum
- Como retorna uma string, você não pode usá-lo para cálculos numéricos.
- Para comparações e buscas, você deve usar o tipo DATETIME original.
3.3 Extrair apenas a parte da data ou hora
Você também pode recuperar partes mantendo o tipo (em vez de formatar para uma string).
SELECT DATE(NOW()); -- date only (DATE type)
SELECT TIME(NOW()); -- time only (TIME type)
SELECT YEAR(NOW()); -- year only
SELECT MONTH(NOW()); -- month only
SELECT DAY(NOW()); -- day only
Uso recomendado
| Goal | Recommended |
|---|---|
| Formatting for display | DATE_FORMAT |
| Calculation / comparison | DATE() / TIME() |
3.4 Exibição com microssegundos
Quando você precisa de logs de alta precisão:
SELECT NOW(6);
Com formatação:
SELECT DATE_FORMAT(NOW(6), '%Y-%m-%d %H:%i:%s.%f');
Notas importantes
- Sua coluna deve ser
DATETIME(6)ouTIMESTAMP(6), caso contrário, a precisão não será armazenada. - Não disponível em versões do MySQL anteriores a 5.6.4 (dependente do ambiente).
Erros comuns
Usar
DATE_FORMAT()em uma cláusula WHERE impede o uso de índices. wp:list /wp:list- Exemplo ruim:
WHERE DATE_FORMAT(created_at, '%Y-%m-%d') = '2025-02-23' - Recomendado:
WHERE created_at >= '2025-02-23 00:00:00' AND created_at < '2025-02-24 00:00:00' - Armazenar a string formatada para exibição diretamente (prejudica o desempenho de busca)
- Exemplo ruim:
Principais lições desta seção
- Use
DATE_FORMAT()para alterar formatos de exibição. - Para cálculos/comparações, mantenha o tipo original.
- Se precisar de microssegundos, especifique a precisão na definição da coluna.
- Usar funções em cláusulas WHERE pode causar problemas de desempenho.
4. Cálculos de datetime usando o tempo atual
No MySQL, é comum calcular coisas como “N horas depois”, “N dias atrás” ou “os últimos N dias” com base no horário atual.
O caso real mais comum é “obter dados das últimas 24 horas.”
A base da aritmética de data/hora é INTERVAL (sintaxe para adicionar/subtrair unidades de tempo).
4.1 Adicionar/subtrair com INTERVAL
Obter 1 hora depois
SELECT NOW() + INTERVAL 1 HOUR;
Obter 3 dias atrás
SELECT NOW() - INTERVAL 3 DAY;
Obter 1 mês depois
SELECT NOW() + INTERVAL 1 MONTH;
Unidades comuns
| Unit | Meaning |
|---|---|
| SECOND | Seconds |
| MINUTE | Minutes |
| HOUR | Hours |
| DAY | Days |
| WEEK | Weeks |
| MONTH | Months |
| YEAR | Years |
Erros comuns
DAYemINTERVAL 1 DAYfunciona mesmo em minúsculas, mas você deve padronizar dentro da equipe.- Cálculos de fim de mês podem diferir das expectativas porque o número de dias varia (ex.: 31 de jan + 1 mês).
4.2 Obter dados das últimas 24 horas (padrão mais comum)
SELECT *
FROM users
WHERE created_at >= NOW() - INTERVAL 1 DAY;
Significado
- Aponta para “a partir de agora até 24 horas atrás.”
Observações
- Se você usar
CURDATE(), a linha de base passa a ser “hoje às 00:00”, o que altera o significado.
Exemplo (dados de hoje):
SELECT *
FROM users
WHERE created_at >= CURDATE();
Entender a diferença é crucial
| Expression | Meaning |
|---|---|
NOW() - INTERVAL 1 DAY | Past 24 hours |
CURDATE() | Since today 00:00 |
4.3 Obter diferenças de dias com DATEDIFF()
SELECT DATEDIFF('2025-03-01', '2025-02-23');
Resultado:
6
- A unidade é “dias”
- A parte de horário é ignorada
Observações
- O sinal muda dependendo da ordem dos argumentos.
- Não é possível calcular diferenças em horas/minutos/segundos.
4.4 Usar TIMESTAMPDIFF() para horas/minutos/segundos
SELECT TIMESTAMPDIFF(HOUR,
'2025-02-23 12:00:00',
'2025-02-23 18:30:00');
Resultado:
6
Minutos
SELECT TIMESTAMPDIFF(MINUTE,
'2025-02-23 12:00:00',
'2025-02-23 12:30:00');
Segundos
SELECT TIMESTAMPDIFF(SECOND,
'2025-02-23 12:00:00',
'2025-02-23 12:00:45');
Casos de uso
- Cálculos de duração de sessão
- Verificações de expiração
- Decisões de timeout
4.5 Obter início/fim do mês (armadilha comum no mundo real)
Obter o primeiro dia deste mês:
SELECT DATE_FORMAT(NOW(), '%Y-%m-01');
Primeiro dia do próximo mês:
SELECT DATE_FORMAT(NOW() + INTERVAL 1 MONTH, '%Y-%m-01');
Observações
- O fim do mês não é uma data fixa.
- Para consultas de intervalo, “>= início E < primeiro dia do próximo mês” é seguro.
Resumo de erros comuns
- Usar
BETWEENcom valores apenas de data e esquecer o horário - Desabilitar índices ao usar
DATE(created_at)nas cláusulas WHERE - Cair na armadilha do “dia 31” em cálculos de mês
- Não compreender a diferença entre
NOW()eCURDATE()
Principais aprendizados desta seção
INTERVALé a base da aritmética de data/hora.- Últimas 24 horas =
NOW() - INTERVAL 1 DAY. - Dias =
DATEDIFF(); unidades menores =TIMESTAMPDIFF(). - Tenha cuidado com as condições de término em cálculos baseados em mês.
5. Para consultas de intervalo, isso é mais seguro que BETWEEN
Ao fazer buscas por intervalo de datas no MySQL, muitos iniciantes usam BETWEEN. Contudo, ele frequentemente produz resultados indesejados se você manipular incorretamente os limites de tempo, portanto um padrão mais seguro é recomendado no trabalho real.
5.1 Noções básicas de BETWEEN e a armadilha
Uma consulta comum
SELECT *
FROM orders
WHERE order_date BETWEEN '2025-02-01' AND '2025-02-10';
Parece correto, mas internamente é equivalente a:
WHERE order_date >= '2025-02-01 00:00:00'
AND order_date <= '2025-02-10 00:00:00'
Portanto não inclui dados após 00:00 em 10 de fev.
5.2 Padrão mais seguro (recomendado)
Padrão recomendado
SELECT *
FROM orders
WHERE order_date >= '2025-02-01 00:00:00'
AND order_date < '2025-02-11 00:00:00';
Pontos principais
- Especifique o limite final como “menor que o próximo dia às 00:00”
- Mais seguro que
<= 23:59:59(suporta microssegundos)
5.3 A maneira correta de obter os dados de hoje
Bad example:
WHERE DATE(created_at) = CURDATE();
Problems:
- Aplicar uma função à coluna desabilita índices
- Pode causar lentidão grave em tabelas grandes
Recommended:
WHERE created_at >= CURDATE()
AND created_at < CURDATE() + INTERVAL 1 DAY;
This ensures:
- Índices podem ser usados
- Pesquisas rápidas
- Sem problemas de limites
5.4 Padrões seguros para os últimos 7 / últimos 30 dias
Últimos 7 dias
WHERE created_at >= NOW() - INTERVAL 7 DAY;
Últimos 30 dias
WHERE created_at >= NOW() - INTERVAL 30 DAY;
Observações
CURDATE() - INTERVAL 7 DAYbaseia‑se em “hoje 00:00”NOW() - INTERVAL 7 DAYbaseia‑se em “hora atual”- Escolha conforme os requisitos
5.5 Regra chave para manter índices eficazes
Bad:
WHERE DATE(created_at) = '2025-02-23';
Good:
WHERE created_at >= '2025-02-23 00:00:00'
AND created_at < '2025-02-24 00:00:00';
Why:
- Índices funcionam na “própria coluna”
- Aplicar uma função impede o uso do índice (varredura completa)
Resumo de erros comuns
- Esquecer de incluir o horário no limite final em
BETWEEN - Perder microssegundos ao usar
23:59:59 - Usar
DATE()em cláusulas WHERE e desacelerar consultas - Deixar “now” vs “today 00:00” ambíguos
Principais conclusões desta seção
- Consultas de intervalo são mais seguras com
>= start AND < end. BETWEENrequer tratamento cuidadoso dos limites.- Para manter os índices eficazes, não envolva colunas em funções.
- Escolha claramente entre lógica baseada em
NOW()e lógica baseada emCURDATE().
6. DEFAULT CURRENT_TIMESTAMP e ON UPDATE (noções básicas de design de tabelas)
No design de bancos de dados, é comum gerenciar automaticamente created_at e updated_at.
No MySQL, CURRENT_TIMESTAMP permite definir o horário atual automaticamente na inserção e atualização.
6.1 Definir automaticamente created_at (DEFAULT CURRENT_TIMESTAMP)
CREATE TABLE users (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(255),
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
Behavior:
INSERT INTO users (name) VALUES ('Alice');
→ O horário atual é inserido automaticamente em created_at.
Pontos chave
CURRENT_TIMESTAMPpode ser usado em DEFAULT.NOW()não pode ser usado diretamente em DEFAULT.
Erro comum
created_at DATETIME DEFAULT NOW(); -- error
Reason:
- No MySQL, geralmente você não pode definir uma função como DEFAULT (a exceção é CURRENT_TIMESTAMP).
6.2 Atualização automática de updated_at (ON UPDATE)
CREATE TABLE users (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(255),
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
ON UPDATE CURRENT_TIMESTAMP
);
Behavior:
UPDATE users SET name = 'Bob' WHERE id = 1;
→ updated_at é atualizado automaticamente para o horário atual.
Casos de uso
- Rastreamento de último login
- Histórico de atualizações
- Logs de auditoria
6.3 DATETIME vs TIMESTAMP (importante)
| Type | Range | Time zone impact |
|---|---|---|
| DATETIME | Year 1000 to 9999 | No |
| TIMESTAMP | 1970 to 2038 | Yes |
A diferença essencial
TIMESTAMPé armazenado internamente em UTC e convertido para o fuso horário da sessão na exibição.DATETIMEarmazena o valor literal (sem conversão).
Guidelines
| Case | Recommended type |
|---|---|
| Log management | TIMESTAMP |
| Future dates (after 2038) | DATETIME |
| Fixed values not requiring TZ conversion | DATETIME |
6.4 CURRENT_TIMESTAMP também pode ser usado com DATETIME
No MySQL 5.6 e posteriores, você pode especificar CURRENT_TIMESTAMP como DEFAULT e ON UPDATE para colunas DATETIME também.
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
Observações
- Versões mais antigas do MySQL têm restrições (dependentes do ambiente).
- Se precisar de precisão:
DATETIME(6) DEFAULT CURRENT_TIMESTAMP(6)
6.5 Se você quiser usar NOW(): uma alternativa (trigger)
CREATE TRIGGER set_created_at
BEFORE INSERT ON logs
FOR EACH ROW
SET NEW.created_at = NOW();
Casos de uso
- Lógica complexa de valor inicial
- Atribuição condicional de timestamp
Notas
- Triggers são difíceis de depurar.
- Evite-os a menos que necessário.
Erros comuns de design
- Adicionar ON UPDATE a ambos
created_ateupdated_at - Confundir o comportamento de DATETIME e TIMESTAMP
- Adiar decisões sobre fuso horário
Principais lições desta seção
- Use
CURRENT_TIMESTAMPpara DEFAULT. - Use
ON UPDATE CURRENT_TIMESTAMPpara rastreamento de atualizações. - Escolha tipos com base no comportamento de fuso horário e no problema de 2038.
- Se precisar de precisão, não esqueça
(6).
7. Design de fuso horário (armazenar em UTC, exibir no horário local)
Ao lidar com o horário atual, um design ruim de fuso horário causa deriva de tempo e conversão dupla.
Na prática, o padrão mais seguro é “armazenar em UTC, converter para o horário local para exibição.”

Figura: Arquitetura básica para armazenar UTC no MySQL e exibir horário local
7.1 Verificar o fuso horário atual
Primeiro, verifique em qual fuso horário o MySQL está executando.
SELECT @@global.time_zone, @@session.time_zone;
@@global.time_zone→ configuração em todo o servidor@@session.time_zone→ configuração da conexão/sessão atual- Se mostrar
SYSTEM, depende da configuração do SO
Problemas comuns
- Servidores de produção e desenvolvimento têm fusos horários de SO diferentes
- O app converte para UTC, e o BD converte novamente (conversão dupla)
7.2 Alterar o fuso horário por sessão
SET time_zone = 'Asia/Tokyo';
ou unificar para UTC:
SET time_zone = '+00:00';
Pontos importantes
- Ele reverte quando a conexão é fechada
- Se usar pool de conexões, verifique as configurações do aplicativo
7.3 Por que armazenar em UTC (princípio do mundo real)
Política recomendada
- Armazenar dados em UTC
- Converter para o fuso horário do usuário ao exibir
Razões:
- Suporte internacional mais fácil
- Evitar problemas de horário de verão (DST)
- Minimizar impacto ao mover servidores
Obter UTC:
SELECT UTC_TIMESTAMP();
7.4 Converter fusos horários com CONVERT_TZ()
Exemplo: UTC → JST
SELECT CONVERT_TZ('2025-02-23 05:35:00', '+00:00', '+09:00');
Usando nomes de fuso horário:
SELECT CONVERT_TZ('2025-02-23 05:35:00', 'UTC', 'Asia/Tokyo');
Exemplo do mundo real
SELECT CONVERT_TZ(created_at, 'UTC', 'Asia/Tokyo')
FROM users;
7.5 Por que CONVERT_TZ() retorna NULL
Se retornar NULL, causas comuns incluem:
- Tabelas de fuso horário do MySQL não estão carregadas
- O nome de fuso horário especificado não existe
Exemplo de carregamento no Linux:
mysql_tzinfo_to_sql /usr/share/zoneinfo | mysql -u root -p mysql
Notas
- Em produção, confirme permissões e se uma reinicialização é necessária
- No Docker, zoneinfo pode não estar incluído dependendo da imagem
7.6 Alterar o fuso horário em todo o servidor
Arquivo de configuração (my.cnf / my.ini):
[mysqld]
default_time_zone = '+00:00'
Verificar após reinicialização:
SELECT @@global.time_zone;
Importante
- Para alterações em produção, confirme o escopo de impacto
- Tenha cuidado com dados existentes (às vezes apenas a exibição muda)
Erros comuns
- Armazenar horário local em vez de UTC, depois adicionar suporte internacional
- Conversão dupla entre o app e o BD
- Projetar com DATETIME sem considerar fusos horários
- Configurações de TZ diferentes entre teste e produção
Principais lições desta seção
- Armazene em UTC e converta na exibição.
- Use
UTC_TIMESTAMP(). - Ao usar
CONVERT_TZ(), verifique as tabelas de TZ. - Sempre considere diferenças de ambiente em fusos horários.
8. Exemplos práticos que você pode usar como estão
Aqui estão exemplos concretos de SQL mostrando como usar o horário atual do MySQL no desenvolvimento/operações reais.
Eles estão escritos para que você possa copiar e colar diretamente.
8.1 Inserir automaticamente o horário atual em logs
Criar tabela
CREATE TABLE system_logs (
id INT AUTO_INCREMENT PRIMARY KEY,
level VARCHAR(50),
message TEXT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
Inserir log
INSERT INTO system_logs (level, message)
VALUES ('ERROR', 'Failed to connect to the DB');
Pontos principais
created_até inserido automaticamente- Não é necessário passar um timestamp do aplicativo
- Design essencial para auditoria e investigação de incidentes
Erros comuns
- Gerenciar tempo tanto no aplicativo quanto no BD
- Inconsistências de tempo devido a fusos horários não unificados
8.2 Atualizar o horário do último login
Design da tabela
CREATE TABLE users (
id INT AUTO_INCREMENT PRIMARY KEY,
username VARCHAR(255),
last_login TIMESTAMP DEFAULT CURRENT_TIMESTAMP
ON UPDATE CURRENT_TIMESTAMP
);
Atualizar no login
UPDATE users
SET last_login = NOW()
WHERE id = 1;
Observações
ON UPDATEdispara apenas quando a coluna muda- Algumas instruções UPDATE podem não alterar o valor e, portanto, não atualizar
8.3 Fixar um tempo de referência em jobs em lote
Para processos de longa duração, é mais seguro fixar um tempo de referência.
SET @base_time = NOW();
SELECT *
FROM orders
WHERE created_at >= @base_time - INTERVAL 1 DAY;
Por que
- O tempo não muda durante o processo
- A consistência é mantida
8.4 Agregação para hoje / ontem / últimos 7 dias
Vendas de hoje
SELECT SUM(amount)
FROM orders
WHERE created_at >= CURDATE()
AND created_at < CURDATE() + INTERVAL 1 DAY;
Vendas de ontem
SELECT SUM(amount)
FROM orders
WHERE created_at >= CURDATE() - INTERVAL 1 DAY
AND created_at < CURDATE();
Últimos 7 dias
SELECT COUNT(*)
FROM users
WHERE created_at >= NOW() - INTERVAL 7 DAY;
Importante
- Não aplique funções às colunas nas cláusulas WHERE
- Escreva condições que mantenham os índices utilizáveis
8.5 Verificações de expiração (sessões/tokens)
SELECT *
FROM sessions
WHERE expires_at > NOW();
Excluir linhas expiradas
DELETE FROM sessions
WHERE expires_at <= NOW();
Erros comuns
- Usar
CURDATE()e ignorar o horário - Armazenar em UTC mas comparar com
NOW()local
8.6 Obter linhas que expiram dentro de N horas
SELECT *
FROM coupons
WHERE expires_at <= NOW() + INTERVAL 1 HOUR;
Casos de uso:
- Alertas de expiração
- Notificações de expiração
O que você deve sempre ter em mente
- Seja explícito se sua referência é “agora” ou “hoje 00:00”
- Escreva predicados que mantenham os índices eficazes
- Decida o design de fuso horário antecipadamente
- Não misture
NOW()eUTC_TIMESTAMP()sem uma política clara
Principais conclusões desta seção
- Para logs/auditorias/registro de atualizações, use
CURRENT_TIMESTAMP - Para agregação, use o padrão seguro
>= AND < - Para gerenciamento de sessões, compare com
NOW() - Fixe um tempo de referência para manter o processamento consistente
9. Perguntas Frequentes (FAQ)
Aqui estão perguntas comuns sobre o horário atual do MySQL, especialmente as armadilhas que surgem no trabalho real.
9.1 Qual é a diferença entre NOW() e CURRENT_TIMESTAMP?
Conclusão: o significado do valor retornado é o mesmo.
SELECT NOW(), CURRENT_TIMESTAMP;
Ambos retornam a data e hora atuais.
A principal diferença é o uso sintático
CURRENT_TIMESTAMPpode ser usado emDEFAULTeON UPDATENOW()não pode ser usado diretamente em DEFAULT
Observações
- Não é uma diferença de tipo
- Você pode especificar precisão com argumentos como
(6)
9.2 Você deve usar SYSDATE()?
SYSDATE() retorna o horário no “momento da avaliação.”
SELECT SYSDATE(), SLEEP(2), SYSDATE();
O valor pode mudar mesmo dentro da mesma consulta.
Quando usar
- Quando precisar registrar o instante de tempo real exato
Quando evitar
- Replicação
- Processamento de transações onde a consistência importa
Na maioria dos casos, usar NOW() é suficiente.
9.3 Por que o horário está deslocado?
Main causes:
- Server time zone settings
- Session time zone settings
- Double conversion with the application
- Automatic conversion behavior of the TIMESTAMP type
Check with:
SELECT @@global.time_zone, @@session.time_zone;
Mitigation
- Store in UTC by default
- Convert only when displaying
- Unify the policy between app and DB
9.4 CONVERT_TZ() returns NULL
Causes:
- Time zone tables are not loaded
- Incorrect time zone name
Fix:
mysql_tzinfo_to_sql /usr/share/zoneinfo | mysql -u root -p mysql
Be especially careful in Docker environments.
9.5 Range shifts with BETWEEN
Bad:
WHERE created_at BETWEEN '2025-02-01' AND '2025-02-10';
Safe:
WHERE created_at >= '2025-02-01 00:00:00'
AND created_at < '2025-02-11 00:00:00';
Reasons:
- End boundary time issue
- Microseconds leakage
- Index efficiency
9.6 How do you choose between DATETIME and TIMESTAMP?
- International support / UTC management → TIMESTAMP
- After 2038 or fixed datetimes → DATETIME
Decide this during design.
9.7 Microseconds aren’t being stored
Cause:
- No precision specified in the column definition
Fix:
created_at DATETIME(6)
Key takeaways from this section
- Start with
NOW()andCURRENT_TIMESTAMP - For range queries, use
>= AND < - UTC storage is the safest default
- Don’t forget type selection and precision
10. Summary
This article organized practical ways to retrieve, format, calculate, and manage the current time in MySQL.
Finally, here are the minimum essentials you should know to stay safe.
10.1 Getting the current time (basics)
- General retrieval →
NOW() - Table DEFAULT / update tracking →
CURRENT_TIMESTAMP - Date only →
CURDATE() - Time only →
CURTIME() - UTC →
UTC_TIMESTAMP() - High precision →
NOW(6)
Rules of thumb
- If unsure, using
NOW()is fine in most cases. - For schema design, use
CURRENT_TIMESTAMP.
10.2 Range queries: “>= AND <” is the golden rule
Safe pattern:
WHERE created_at >= 'START'
AND created_at < 'END'
Why:
- Prevents missing end-boundary rows
- Works with microseconds
- Keeps indexes usable
Bad example
WHERE DATE(created_at) = CURDATE();
Don’t wrap the column in a function.
10.3 Datetime arithmetic basics
- Add/subtract →
INTERVAL - Day differences →
DATEDIFF() - Time differences →
TIMESTAMPDIFF()
Always keep in mind whether your baseline is “now” or “today 00:00.”
10.4 Time zone design principles
- Store in UTC
- Convert on display
- Unify policy between app and DB
Check with:
SELECT @@global.time_zone, @@session.time_zone;
10.5 Table design best practices
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
ON UPDATE CURRENT_TIMESTAMP
- Standard equipment for auditing/logging/update tracking
- If you need precision, specify
(6)
The 4 most important real-world points
- Don’t misunderstand the difference between
NOW()andCURRENT_TIMESTAMP - For range queries, use
>= AND < - Store in UTC by default
- Decide types (DATETIME vs TIMESTAMP) during design
MySQL current time handling is foundational for logging, sales aggregation, auth/session management, batch jobs, and more.
If you follow the principles in this article, you can avoid many common problems such as time drift, boundary bugs, and performance degradation.


