Timestamp Atual do MySQL: NOW(), CURRENT_TIMESTAMP, SYSDATE(), UTC e Melhores Práticas

目次

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 caseRecommended function
General current datetimeNOW()
Table default valueCURRENT_TIMESTAMP
Date onlyCURDATE()
Time onlyCURTIME()
Unified UTC managementUTC_TIMESTAMP()
High-precision logsNOW(6)

Pontos principais que as pessoas frequentemente perdem

  • NOW() e CURRENT_TIMESTAMP sã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_TIMESTAMP também pode ser usado com sintaxe de chamada de função:
    SELECT CURRENT_TIMESTAMP();
    

Como escolher em projetos reais

Use caseRecommended
Simple retrievalNOW()
Table DEFAULT / ON UPDATECURRENT_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

FunctionWhen 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 que CURDATE()
  • CURRENT_TIME → mesmo que CURTIME()
  • LOCALTIME → mesmo que NOW()

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() e CURRENT_TIMESTAMP significam 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_TIMESTAMP para 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

SpecifierMeaningExample
%Y4-digit year2025
%m2-digit month02
%d2-digit day23
%HHour (24-hour)14
%iMinutes35
%sSeconds50
%fMicroseconds123456

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

GoalRecommended
Formatting for displayDATE_FORMAT
Calculation / comparisonDATE() / 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) ou TIMESTAMP(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)

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

UnitMeaning
SECONDSeconds
MINUTEMinutes
HOURHours
DAYDays
WEEKWeeks
MONTHMonths
YEARYears

Erros comuns

  • DAY em INTERVAL 1 DAY funciona 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

ExpressionMeaning
NOW() - INTERVAL 1 DAYPast 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 BETWEEN com 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() e CURDATE()

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 &gt;= '2025-02-01 00:00:00'
  AND order_date &lt;= '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 &gt;= '2025-02-01 00:00:00'
  AND order_date &lt;  '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 &gt;= CURDATE()
  AND created_at &lt;  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 &gt;= NOW() - INTERVAL 7 DAY;

Últimos 30 dias

WHERE created_at &gt;= NOW() - INTERVAL 30 DAY;

Observações

  • CURDATE() - INTERVAL 7 DAY baseia‑se em “hoje 00:00”
  • NOW() - INTERVAL 7 DAY baseia‑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 &gt;= '2025-02-23 00:00:00'
  AND created_at &lt;  '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 .
  • BETWEEN requer 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 em CURDATE().

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_TIMESTAMP pode 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)

TypeRangeTime zone impact
DATETIMEYear 1000 to 9999No
TIMESTAMP1970 to 2038Yes

A diferença essencial

  • TIMESTAMP é armazenado internamente em UTC e convertido para o fuso horário da sessão na exibição.
  • DATETIME armazena o valor literal (sem conversão).

Guidelines

CaseRecommended type
Log managementTIMESTAMP
Future dates (after 2038)DATETIME
Fixed values not requiring TZ conversionDATETIME

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_at e updated_at
  • Confundir o comportamento de DATETIME e TIMESTAMP
  • Adiar decisões sobre fuso horário

Principais lições desta seção

  • Use CURRENT_TIMESTAMP para DEFAULT.
  • Use ON UPDATE CURRENT_TIMESTAMP para 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.”

MySQL timezone architecture storing timestamps in UTC and converting to local time (JST)

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

  1. Armazenar dados em UTC
  2. 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 UPDATE dispara 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 &gt;= @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 &gt;= CURDATE()
  AND created_at &lt;  CURDATE() + INTERVAL 1 DAY;

Vendas de ontem

SELECT SUM(amount)
FROM orders
WHERE created_at &gt;= CURDATE() - INTERVAL 1 DAY
  AND created_at &lt;  CURDATE();

Últimos 7 dias

SELECT COUNT(*)
FROM users
WHERE created_at &gt;= 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 &gt; NOW();

Excluir linhas expiradas

DELETE FROM sessions
WHERE expires_at &lt;= 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 &lt;= 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() e UTC_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_TIMESTAMP pode ser usado em DEFAULT e ON UPDATE
  • NOW() 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:

  1. Server time zone settings
  2. Session time zone settings
  3. Double conversion with the application
  4. 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 &gt;= '2025-02-01 00:00:00'
  AND created_at &lt;  '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() and CURRENT_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 &gt;= 'START'
  AND created_at &lt;  '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

  1. Don’t misunderstand the difference between NOW() and CURRENT_TIMESTAMP
  2. For range queries, use >= AND <
  3. Store in UTC by default
  4. 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.