Marca de tiempo actual en MySQL: NOW(), CURRENT_TIMESTAMP, SYSDATE(), UTC y buenas prácticas

目次

1. La consulta SQL más corta para obtener la fecha/hora actual en MySQL

Si deseas obtener la fecha/hora actual en MySQL, las primeras funciones que debes recordar son NOW() y CURRENT_TIMESTAMP. A continuación se presentan los ejemplos SQL más cortos según el caso de uso.

1.1 Obtener la fecha/hora actual (básico)

SELECT NOW();

or

SELECT CURRENT_TIMESTAMP;
  • Ambas devuelven la fecha/hora actual (YYYY-MM-DD HH:MM:SS).
  • Dentro de la misma consulta, la hora se fija en el “momento de inicio de la consulta”.

Casos de uso

  • Registro de eventos
  • Obtener la marca de tiempo de creación de un registro
  • Obtener una hora de referencia

Error común

  • La zona horaria de la aplicación y la zona horaria de la base de datos difieren y se produce un “desplazamiento de tiempo”. → Verifica con SELECT @@session.time_zone;

1.2 Obtener solo la fecha de hoy

SELECT CURDATE();
  • Formato de retorno: YYYY-MM-DD
  • El tipo es DATE (solo fecha, no datetime)

Casos de uso

  • Buscar los datos de “hoy”
  • Agregación diaria

Notas

  • A diferencia de NOW(), no incluye la hora.
  • Si necesitas la hora para consultas de rango, usa NOW().

1.3 Obtener solo la hora actual

SELECT CURTIME();
  • Formato de retorno: HH:MM:SS
  • El tipo es TIME (solo hora)

Casos de uso

  • Mostrar el tiempo de ejecución de un lote
  • Imprimir solo la parte de hora en los registros

Trampa común

  • Debido a que no incluye una fecha, no puedes usarlo para comparaciones datetime.

1.4 Obtener la hora actual en UTC (importante)

SELECT UTC_TIMESTAMP();
  • Devuelve UTC sin importar la zona horaria del servidor.
  • Recomendado para servicios globales.

Política base en proyectos reales

  • Almacenar en UTC
  • Convertir a hora local al mostrar

Notas

  • Si la aplicación ya convierte a UTC, ten cuidado con la doble conversión.

1.5 Obtener milisegundos / microsegundos

SELECT NOW(3);  -- milliseconds (3 digits after the decimal point)
SELECT NOW(6);  -- microseconds (6 digits after the decimal point)
  • Disponible en MySQL 5.6.4 y posteriores.
  • Utilizado para registros de alta precisión y auditoría de transacciones.

Idea errónea común

  • NOW() por sí solo no puede devolver segundos fraccionarios.
  • Tu columna también debe especificar precisión, por ejemplo DATETIME(6).

1.6 Mejor función según el caso de uso (comienza aquí si no estás seguro)

Use caseRecommended function
General current datetimeNOW()
Table default valueCURRENT_TIMESTAMP
Date onlyCURDATE()
Time onlyCURTIME()
Unified UTC managementUTC_TIMESTAMP()
High-precision logsNOW(6)

Puntos clave que la gente suele pasar por alto

  • NOW() y CURRENT_TIMESTAMP son efectivamente equivalentes (mismo valor)
  • Dentro de la misma consulta, la hora está fija
  • El valor mostrado cambia según la configuración de zona horaria
  • Para microsegundos, la definición de tu columna debe especificar precisión

2. Diferencias entre NOW() / CURRENT_TIMESTAMP / SYSDATE()

Existen varias funciones para obtener la hora actual, pero la parte más confusa es la diferencia entre NOW(), CURRENT_TIMESTAMP y SYSDATE(). Si no comprendes esto correctamente, puedes obtener comportamientos inesperados en los registros y en el procesamiento de transacciones.

2.1 NOW() y CURRENT_TIMESTAMP son efectivamente equivalentes

SELECT NOW(), CURRENT_TIMESTAMP;
  • Ambas devuelven el datetime actual (un valor DATETIME).
  • Dentro de la misma consulta, la hora se fija en el “momento de inicio de la consulta”.
  • CURRENT_TIMESTAMP también puede usarse con sintaxis de llamada a función:
    SELECT CURRENT_TIMESTAMP();
    

Cómo elegir en proyectos reales

Use caseRecommended
Simple retrievalNOW()
Table DEFAULT / ON UPDATECURRENT_TIMESTAMP

Puntos importantes

  • El significado del valor obtenido es el mismo.
  • La principal diferencia es la sintaxis/uso (p.ej., permitido en DEFAULT).
  • No es una diferencia de tipo (fácil de malinterpretar).

2.2 SYSDATE() devuelve la hora en el “momento de evaluación”

SYSDATE() se parece a NOW(), pero el momento en que el valor se fija es diferente.

SELECT NOW(), SLEEP(2), NOW();

Resultado (ejemplo):

2025-02-23 14:00:00
2025-02-23 14:00:00
SELECT SYSDATE(), SLEEP(2), SYSDATE();

Resultado (ejemplo):

2025-02-23 14:00:00
2025-02-23 14:00:02

La diferencia esencial

FunctionWhen the time is fixed
NOW()Query start time
SYSDATE()Evaluation time

2.3 Notas para transacciones y replicación

Debido a que NOW() se fija al inicio de la consulta, es
más seguro cuando necesitas un tiempo de referencia consistente dentro de una transacción.

Por otro lado, dado que SYSDATE() depende del momento de ejecución, puede afectar la reproducibilidad en:

  • Replicación
  • Trabajos por lotes
  • Procesamiento masivo de registros

Regla general

  • Quieres un tiempo de referencia fijo → NOW()
  • Necesitas el instante exacto en todo momento → SYSDATE() (uso limitado)

2.4 Nota: CURRENT_DATE / CURRENT_TIME / LOCALTIME

MySQL también soporta:

SELECT CURRENT_DATE;
SELECT CURRENT_TIME;
SELECT LOCALTIME;
  • CURRENT_DATE → lo mismo que CURDATE()
  • CURRENT_TIME → lo mismo que CURTIME()
  • LOCALTIME → lo mismo que NOW()

Confusión común

  • Estas son mayormente “diferencias cosméticas”; hay poca diferencia funcional.
  • Por seguridad, prioriza la legibilidad y estandariza dentro del proyecto.

Puntos clave de esta sección

  • NOW() y CURRENT_TIMESTAMP significan esencialmente lo mismo.
  • SYSDATE() se comporta de manera diferente porque se basa en el tiempo de evaluación.
  • Para tiempos de referencia fijos, usa NOW() por defecto.
  • Usa CURRENT_TIMESTAMP para DEFAULT y ON UPDATE.

3. Cambiar el formato de visualización de la fecha/hora actual

El tiempo actual que obtienes con NOW() se muestra por defecto como YYYY-MM-DD HH:MM:SS. En el trabajo real, a menudo necesitarás cosas como:

  • Mostrar solo la fecha
  • Usar YYYY/MM/DD
  • Usar un formato localizado (p.ej., 23 de feb. de 2025)
  • Mostrar milisegundos

Para esto, usa DATE_FORMAT() (convierte un datetime a un formato de cadena arbitrario).

3.1 Sintaxis básica de DATE_FORMAT()

DATE_FORMAT(datetime, 'format_string')

Ejemplo: Convertir el tiempo actual a YYYY/MM/DD HH:MM

SELECT DATE_FORMAT(NOW(), '%Y/%m/%d %H:%i');

Ejemplo de salida:

2025/02/23 14:35

Especificadores de formato comunes

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

Notas

  • Algunos especificadores difieren entre mayúsculas y minúsculas.
  • %h es hora en formato de 12 horas, %H es hora en formato de 24 horas.

3.2 Ejemplos de formatos comunes (frecuentes en el trabajo real)

1. Separado por barras

SELECT DATE_FORMAT(NOW(), '%Y/%m/%d');

2. Localizado (Inglés)

SELECT DATE_FORMAT(NOW(), '%b %d, %Y');

3. Sin segundos

SELECT DATE_FORMAT(NOW(), '%Y-%m-%d %H:%i');

Trampa común

  • Debido a que devuelve una cadena, no puedes usarlo para cálculos numéricos.
  • Para comparaciones y búsquedas, deberías usar el tipo DATETIME original.

3.3 Extraer solo la parte de fecha o hora

También puedes obtener partes manteniendo el tipo (en lugar de formatear a una cadena).

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 Mostrar con microsegundos

Cuando necesitas registros de alta precisión:

SELECT NOW(6);

Con formato:

SELECT DATE_FORMAT(NOW(6), '%Y-%m-%d %H:%i:%s.%f');

Notas importantes

  • Tu columna debe ser DATETIME(6) o TIMESTAMP(6), de lo contrario la precisión no se almacenará.
  • No disponible en versiones de MySQL anteriores a la 5.6.4 (dependiendo del entorno).

Errores comunes

  • Usar DATE_FORMAT() en una cláusula WHERE impide que se usen índices. wp:list /wp:list

    • Mal ejemplo: 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'
    • Almacenar directamente la cadena con formato de visualización (daña el rendimiento de búsqueda)

Puntos clave de esta sección

  • Usa DATE_FORMAT() para cambiar los formatos de visualización.
  • Para cálculos/comparaciones, mantén el tipo original.
  • Si necesitas microsegundos, especifica la precisión en la definición de la columna.
  • Usar funciones en cláusulas WHERE puede causar problemas de rendimiento.

4. Cálculos de datetime usando la hora actual

En MySQL, es común calcular cosas como “N horas después”, “N días atrás” o “los últimos N días” basándose en la hora actual.
El caso real más frecuente es “obtener datos de las últimas 24 horas.”

La base de la aritmética de fechas y horas es INTERVAL (sintaxis para añadir/restar unidades de tiempo).

4.1 Añadir/restar con INTERVAL

Obtener 1 hora después

SELECT NOW() + INTERVAL 1 HOUR;

Obtener 3 días atrás

SELECT NOW() - INTERVAL 3 DAY;

Obtener 1 mes después

SELECT NOW() + INTERVAL 1 MONTH;

Unidades comunes

UnitMeaning
SECONDSeconds
MINUTEMinutes
HOURHours
DAYDays
WEEKWeeks
MONTHMonths
YEARYears

Errores comunes

  • DAY en INTERVAL 1 DAY funciona incluso en minúsculas, pero deberías estandarizarlo dentro del equipo.
  • Los cálculos al final del mes pueden diferir de lo esperado porque el número de días varía (p. ej., 31 de enero + 1 mes).

4.2 Obtener datos de las últimas 24 horas (patrón más común)

SELECT *
FROM users
WHERE created_at >= NOW() - INTERVAL 1 DAY;

Significado

  • Apunta a “desde ahora hasta hace 24 horas”.

Notas

  • Si utilizas CURDATE(), la referencia pasa a ser “hoy a 00:00”, lo que cambia el significado.

Ejemplo (datos de hoy):

SELECT *
FROM users
WHERE created_at >= CURDATE();

Entender la diferencia es crucial

ExpressionMeaning
NOW() - INTERVAL 1 DAYPast 24 hours
CURDATE()Since today 00:00

4.3 Obtener diferencias de días con DATEDIFF()

SELECT DATEDIFF('2025-03-01', '2025-02-23');

Resultado:

6
  • La unidad es “días”
  • La parte de tiempo se ignora

Notas

  • El signo cambia según el orden de los argumentos.
  • No puedes calcular diferencias en 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 duración de sesiones
  • Verificaciones de expiración
  • Decisiones de tiempo de espera

4.5 Obtener inicio de mes / fin de mes (trampa común en el mundo real)

Obtener el primer día de este mes:

SELECT DATE_FORMAT(NOW(), '%Y-%m-01');

Primer día del próximo mes:

SELECT DATE_FORMAT(NOW() + INTERVAL 1 MONTH, '%Y-%m-01');

Notas

  • El fin de mes no es una fecha fija.
  • Para consultas de rango, “>= inicio AND < primer día del próximo mes” es seguro.

Resumen de errores comunes

  • Usar BETWEEN con valores solo de fecha y olvidar la hora
  • Desactivar índices al usar DATE(created_at) en cláusulas WHERE
  • Quedarse atrapado por el problema del “día 31” en cálculos de mes
  • No comprender la diferencia entre NOW() y CURDATE()

Puntos clave de esta sección

  • INTERVAL es la base de la aritmética de fechas y horas.
  • Últimas 24 horas = NOW() - INTERVAL 1 DAY.
  • Días = DATEDIFF(); unidades menores = TIMESTAMPDIFF().
  • Ten cuidado con las condiciones finales en cálculos basados en meses.

5. Para consultas de rango, esto es más seguro que BETWEEN

Al realizar búsquedas de rangos de fechas en MySQL, muchos principiantes usan BETWEEN. Sin embargo, a menudo produce resultados no deseados si manejas incorrectamente los límites de tiempo, por lo que se recomienda un patrón más seguro en el trabajo real.

5.1 Conceptos básicos de BETWEEN y la trampa

Una consulta común

SELECT *
FROM orders
WHERE order_date BETWEEN '2025-02-01' AND '2025-02-10';

Parece correcta, pero internamente es equivalente a:

WHERE order_date &gt;= '2025-02-01 00:00:00'
  AND order_date &lt;= '2025-02-10 00:00:00'

Así que no incluye datos después de las 00:00 del 10 de febrero.


5.2 Patrón más seguro (recomendado)

Patrón recomendado

SELECT *
FROM orders
WHERE order_date &gt;= '2025-02-01 00:00:00'
  AND order_date &lt;  '2025-02-11 00:00:00';

Puntos clave

  • Especifica el límite final como “menor que el siguiente día a las 00:00”
  • Más seguro que <= 23:59:59 (soporta microsegundos)

5.3 La forma correcta de obtener los datos de hoy

Ejemplo malo:

WHERE DATE(created_at) = CURDATE();

Problemas:

  • Aplicar una función a la columna desactiva los índices
  • Puede causar ralentizaciones graves en tablas grandes

Recomendado:

WHERE created_at &gt;= CURDATE()
  AND created_at &lt;  CURDATE() + INTERVAL 1 DAY;

Esto asegura:

  • Se pueden usar índices
  • Búsquedas rápidas
  • Sin problemas de límites

5.4 Patrones seguros para los últimos 7 / últimos 30 días

Últimos 7 días

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

Últimos 30 días

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

Notas

  • CURDATE() - INTERVAL 7 DAY se basa en “hoy 00:00”
  • NOW() - INTERVAL 7 DAY se basa en “hora actual”
  • Elige según los requisitos

5.5 Regla clave para mantener los índices efectivos

Malo:

WHERE DATE(created_at) = '2025-02-23';

Bueno:

WHERE created_at &gt;= '2025-02-23 00:00:00'
  AND created_at &lt;  '2025-02-24 00:00:00';

Por qué:

  • Los índices funcionan en “la columna misma”
  • Aplicar una función impide el uso de índices (escaneo completo)

Resumen de errores comunes

  • Olvidar incluir la hora en el límite final en BETWEEN
  • Falta de microsegundos al usar 23:59:59
  • Usar DATE() en cláusulas WHERE y ralentizar consultas
  • Dejar ambiguo “ahora” vs “hoy 00:00”

Lecciones clave de esta sección

  • Las consultas de rango son más seguras con >= inicio AND < fin .
  • BETWEEN requiere un manejo cuidadoso de los límites.
  • Para mantener los índices efectivos, no envuelvas las columnas en funciones.
  • Elige claramente entre lógica basada en NOW() y basada en CURDATE().

6. DEFAULT CURRENT_TIMESTAMP y ON UPDATE (básicos del diseño de tablas)

En el diseño de bases de datos, es común gestionar automáticamente created_at y updated_at.
En MySQL, CURRENT_TIMESTAMP te permite establecer la hora actual automáticamente en inserciones y actualizaciones.

6.1 Configuración automática de created_at (DEFAULT CURRENT_TIMESTAMP)

CREATE TABLE users (
    id INT AUTO_INCREMENT PRIMARY KEY,
    name VARCHAR(255),
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

Comportamiento:

INSERT INTO users (name) VALUES ('Alice');

→ La hora actual se inserta automáticamente en created_at.

Puntos clave

  • CURRENT_TIMESTAMP se puede usar en DEFAULT.
  • NOW() no se puede usar directamente en DEFAULT.

Error común

created_at DATETIME DEFAULT NOW();  -- error

Razón:

  • En MySQL, generalmente no puedes establecer una función como DEFAULT (la excepción es CURRENT_TIMESTAMP).

6.2 Actualización 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
);

Comportamiento:

UPDATE users SET name = 'Bob' WHERE id = 1;

updated_at se actualiza automáticamente a la hora actual.

Casos de uso

  • Seguimiento del último inicio de sesión
  • Historial de actualizaciones
  • Registros de auditoría

6.3 DATETIME vs TIMESTAMP (importante)

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

La diferencia esencial

  • TIMESTAMP se almacena internamente en UTC y se convierte a la zona horaria de la sesión al mostrarlo.
  • DATETIME almacena el valor literal (sin conversión).

Guías

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

6.4 CURRENT_TIMESTAMP también se puede usar con DATETIME

En MySQL 5.6 y posteriores, puedes especificar CURRENT_TIMESTAMP como DEFAULT y ON UPDATE para columnas DATETIME también.

created_at DATETIME DEFAULT CURRENT_TIMESTAMP

Notas

  • Las versiones antiguas de MySQL tienen restricciones (dependientes del entorno).
  • Si necesitas precisión:
    DATETIME(6) DEFAULT CURRENT_TIMESTAMP(6)
    

6.5 Si quieres usar NOW(): una alternativa (trigger)

CREATE TRIGGER set_created_at
BEFORE INSERT ON logs
FOR EACH ROW
SET NEW.created_at = NOW();

Casos de uso

  • Lógica compleja de valores iniciales
  • Asignación condicional de marcas de tiempo

Notas

  • Los desencadenadores son difíciles de depurar.
  • Evítalos a menos que sea necesario.

Errores de diseño comunes

  • Agregar ON UPDATE a tanto created_at como updated_at
  • Confundir el comportamiento de DATETIME y TIMESTAMP
  • Postergar decisiones sobre zonas horarias

Lecciones clave de esta sección

  • Usa CURRENT_TIMESTAMP para DEFAULT.
  • Usa ON UPDATE CURRENT_TIMESTAMP para el seguimiento de actualizaciones.
  • Elige tipos según el comportamiento de zonas horarias y el problema del año 2038.
  • Si necesitas precisión, no olvides (6) .

7. Diseño de zonas horarias (almacenar en UTC, mostrar en hora local)

Al trabajar con la hora actual, un mal diseño de zonas horarias causa deriva temporal y conversiones dobles.
En la práctica, el enfoque predeterminado más seguro es “almacenar en UTC, convertir a hora local para mostrar.”

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

Figura: Arquitectura básica para almacenar UTC en MySQL y mostrar hora local

7.1 Verificar la zona horaria actual

Primero, verifica en qué zona horaria se ejecuta MySQL.

SELECT @@global.time_zone, @@session.time_zone;
  • @@global.time_zone → configuración a nivel de servidor
  • @@session.time_zone → configuración de la conexión/sesión actual
  • Si muestra SYSTEM , depende de la configuración del SO

Problemas comunes

  • Los servidores de producción y desarrollo tienen zonas horarias de SO diferentes
  • La aplicación convierte a UTC, y la BD convierte nuevamente (conversión doble)

7.2 Cambiar la zona horaria por sesión

SET time_zone = 'Asia/Tokyo';

o unificar a UTC:

SET time_zone = '+00:00';

Puntos importantes

  • Revierte cuando se cierra la conexión
  • Si usas agrupación de conexiones, verifica la configuración de tu aplicación

7.3 Por qué almacenar en UTC (principio del mundo real)

Política recomendada

  1. Almacena datos en UTC
  2. Convierte a la zona horaria del usuario al mostrar

Razones:

  • Soporte internacional más fácil
  • Evita problemas de horario de verano (DST)
  • Minimiza el impacto al mover servidores

Obtén UTC:

SELECT UTC_TIMESTAMP();

7.4 Convertir zonas horarias con CONVERT_TZ()

Ejemplo: UTC → JST

SELECT CONVERT_TZ('2025-02-23 05:35:00', '+00:00', '+09:00');

Usando nombres de zonas horarias:

SELECT CONVERT_TZ('2025-02-23 05:35:00', 'UTC', 'Asia/Tokyo');

Ejemplo del mundo real

SELECT CONVERT_TZ(created_at, 'UTC', 'Asia/Tokyo')
FROM users;

7.5 Por qué CONVERT_TZ() devuelve NULL

Si devuelve NULL, las causas comunes incluyen:

  • Las tablas de zonas horarias de MySQL no están cargadas
  • El nombre de zona horaria especificado no existe

Ejemplo de carga en Linux:

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

Notas

  • En producción, confirma permisos y si se requiere un reinicio
  • En Docker, zoneinfo puede no estar incluido dependiendo de la imagen

7.6 Cambiar la zona horaria a nivel de servidor

Archivo de configuración (my.cnf / my.ini):

[mysqld]
default_time_zone = '+00:00'

Verifica después del reinicio:

SELECT @@global.time_zone;

Importante

  • Para cambios en producción, confirma el alcance del impacto
  • Ten cuidado con datos existentes (a veces solo cambian las visualizaciones)

Errores comunes

  • Almacenar hora local en lugar de UTC, y luego agregar soporte internacional
  • Conversión doble entre la aplicación y la BD
  • Diseñar con DATETIME sin considerar zonas horarias
  • Configuraciones de TZ diferentes entre pruebas y producción

Lecciones clave de esta sección

  • Almacena en UTC y convierte al mostrar.
  • Usa UTC_TIMESTAMP() .
  • Al usar CONVERT_TZ() , verifica las tablas de TZ.
  • Siempre considera las diferencias de entorno en zonas horarias.

8. Ejemplos prácticos que puedes usar tal cual

Aquí hay ejemplos concretos de SQL que muestran cómo usar la hora actual de MySQL en desarrollo/operaciones reales.
Están escritos para que puedas copiar y pegar directamente.

8.1 Insertar automáticamente la hora actual en registros

Crear tabla

CREATE TABLE system_logs (
    id INT AUTO_INCREMENT PRIMARY KEY,
    level VARCHAR(50),
    message TEXT,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

Insertar registro

INSERT INTO system_logs (level, message)
VALUES ('ERROR', 'Failed to connect to the DB');

Puntos clave

  • created_at se inserta automáticamente
  • No es necesario pasar una marca de tiempo desde la aplicación
  • Diseño esencial para auditoría e investigación de incidentes

Errores comunes

  • Gestionar el tiempo tanto en la aplicación como en la base de datos
  • Inconsistencias de tiempo debido a zonas horarias no unificadas

8.2 Actualizar la hora del último inicio de sesión

Diseño de tabla

CREATE TABLE users (
    id INT AUTO_INCREMENT PRIMARY KEY,
    username VARCHAR(255),
    last_login TIMESTAMP DEFAULT CURRENT_TIMESTAMP
               ON UPDATE CURRENT_TIMESTAMP
);

Actualizar al iniciar sesión

UPDATE users
SET last_login = NOW()
WHERE id = 1;

Notas

  • ON UPDATE se dispara solo cuando la columna cambia
  • Algunas sentencias UPDATE pueden no cambiar el valor y, por lo tanto, no actualizar

8.3 Fijar una hora de referencia en trabajos por lotes

Para procesos de larga duración, es más seguro fijar una hora de referencia.

SET @base_time = NOW();

SELECT *
FROM orders
WHERE created_at &gt;= @base_time - INTERVAL 1 DAY;

Por qué

  • El tiempo no cambia a mitad del proceso
  • Se mantiene la consistencia

8.4 Agregación para hoy / ayer / últimos 7 días

Ventas de hoy

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

Ventas de ayer

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

Últimos 7 días

SELECT COUNT(*)
FROM users
WHERE created_at &gt;= NOW() - INTERVAL 7 DAY;

Importante

  • No aplique funciones a columnas en cláusulas WHERE
  • Escriba condiciones que mantengan los índices utilizables

8.5 Verificaciones de expiración (sesiones/tokenes)

SELECT *
FROM sessions
WHERE expires_at &gt; NOW();

Eliminar filas expiradas

DELETE FROM sessions
WHERE expires_at &lt;= NOW();

Errores comunes

  • Usar CURDATE() e ignorar la hora
  • Almacenar en UTC pero comparar con NOW() local

8.6 Obtener filas que expiran dentro de N horas

SELECT *
FROM coupons
WHERE expires_at &lt;= NOW() + INTERVAL 1 HOUR;

Casos de uso:

  • Alertas de expiración
  • Notificaciones de vencimiento

Lo que siempre debes tener en cuenta

  • Sea explícito si su referencia es “ahora” o “hoy 00:00”
  • Escriba predicados que mantengan los índices efectivos
  • Decida el diseño de zona horaria desde el principio
  • No mezcle NOW() y UTC_TIMESTAMP() sin una política clara

Puntos clave de esta sección

  • Para registros/auditorías/seguimiento de actualizaciones, use CURRENT_TIMESTAMP
  • Para agregación, use el patrón seguro >= AND <
  • Para gestión de sesiones, compare con NOW()
  • Fije una hora de referencia para mantener el procesamiento consistente

9. Preguntas Frecuentes (FAQ)

Aquí hay preguntas comunes sobre la hora actual en MySQL, especialmente los inconvenientes que aparecen en el trabajo real.

9.1 ¿Cuál es la diferencia entre NOW() y CURRENT_TIMESTAMP?

Conclusión: el significado del valor devuelto es el mismo.

SELECT NOW(), CURRENT_TIMESTAMP;

Ambos devuelven la fecha y hora actuales.

La principal diferencia es el uso sintáctico

  • CURRENT_TIMESTAMP puede usarse en DEFAULT y ON UPDATE
  • NOW() no puede usarse directamente en DEFAULT

Notas

  • No es una diferencia de tipo
  • Puede especificar precisión con argumentos como (6)

9.2 ¿Debería usar SYSDATE()?

SYSDATE() devuelve la hora en el “momento de evaluación”.

SELECT SYSDATE(), SLEEP(2), SYSDATE();

El valor puede cambiar incluso dentro de la misma consulta.

Cuándo usarlo

  • Cuando necesita registrar el instante de tiempo real exacto

Cuándo evitarlo

  • Replicación
  • Procesamiento de transacciones donde la consistencia es importante

En la mayoría de los casos, usar NOW() es suficiente.

9.3 ¿Por qué se desplaza la hora?

Causas principales:

  1. Configuraciones de zona horaria del servidor
  2. Configuraciones de zona horaria de la sesión
  3. Conversión doble con la aplicación
  4. Comportamiento de conversión automática del tipo TIMESTAMP

Verificar con:

SELECT @@global.time_zone, @@session.time_zone;

Mitigación

  • Almacenar en UTC por defecto
  • Convertir solo al mostrar
  • Unificar la política entre la app y la DB

9.4 CONVERT_TZ() devuelve NULL

Causas:

  • Las tablas de zona horaria no están cargadas
  • Nombre de zona horaria incorrecto

Solución:

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

Tener especial cuidado en entornos Docker.

9.5 Desplazamientos de rango con BETWEEN

Malo:

WHERE created_at BETWEEN '2025-02-01' AND '2025-02-10';

Seguro:

WHERE created_at &gt;= '2025-02-01 00:00:00'
  AND created_at &lt;  '2025-02-11 00:00:00';

Razones:

  • Problema con el tiempo de límite final
  • Fuga de microsegundos
  • Eficiencia del índice

9.6 ¿Cómo elegir entre DATETIME y TIMESTAMP?

  • Soporte internacional / gestión de UTC → TIMESTAMP
  • Después de 2038 o datetimes fijos → DATETIME

Decidir esto durante el diseño.

9.7 No se están almacenando microsegundos

Causa:

  • No se especificó precisión en la definición de la columna

Solución:

created_at DATETIME(6)

Lecciones clave de esta sección

  • Comenzar con NOW() y CURRENT_TIMESTAMP
  • Para consultas de rango, usar >= AND <
  • El almacenamiento en UTC es el valor predeterminado más seguro
  • No olvidar la selección de tipos y la precisión

10. Resumen

Este artículo organizó formas prácticas de recuperar, formatear, calcular y gestionar la hora actual en MySQL.
Finalmente, aquí están los mínimos esenciales que debes conocer para mantenerte seguro.

10.1 Obtener la hora actual (básicos)

  • Recuperación general → NOW()
  • DEFAULT de tabla / seguimiento de actualizaciones → CURRENT_TIMESTAMP
  • Solo fecha → CURDATE()
  • Solo hora → CURTIME()
  • UTC → UTC_TIMESTAMP()
  • Alta precisión → NOW(6)

Reglas generales

  • Si no estás seguro, usar NOW() está bien en la mayoría de los casos.
  • Para el diseño de esquema, usar CURRENT_TIMESTAMP .

10.2 Consultas de rango: “>= AND <” es la regla de oro

Patrón seguro:

WHERE created_at &gt;= 'START'
  AND created_at &lt;  'END'

Por qué:

  • Evita perder filas en el límite final
  • Funciona con microsegundos
  • Mantiene los índices utilizables

Ejemplo malo

WHERE DATE(created_at) = CURDATE();

No envuelvas la columna en una función.

10.3 Conceptos básicos de aritmética de datetime

  • Sumar/restar → INTERVAL
  • Diferencias de días → DATEDIFF()
  • Diferencias de tiempo → TIMESTAMPDIFF()

Siempre ten en mente si tu línea base es “ahora” o “hoy 00:00”.

10.4 Principios de diseño de zona horaria

  • Almacenar en UTC
  • Convertir al mostrar
  • Unificar la política entre la app y la DB

Verificar con:

SELECT @@global.time_zone, @@session.time_zone;

10.5 Mejores prácticas de diseño de tabla

created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
           ON UPDATE CURRENT_TIMESTAMP
  • Equipo estándar para auditoría/registro/seguimiento de actualizaciones
  • Si necesitas precisión, especifica (6)

Los 4 puntos más importantes del mundo real

  1. No malinterpretes la diferencia entre NOW() y CURRENT_TIMESTAMP
  2. Para consultas de rango, usar >= AND <
  3. Almacenar en UTC por defecto
  4. Decidir tipos (DATETIME vs TIMESTAMP) durante el diseño

El manejo de la hora actual en MySQL es fundamental para el registro, agregación de ventas, gestión de autenticación/sesiones, trabajos en lotes y más.
Si sigues los principios en este artículo, puedes evitar muchos problemas comunes como deriva de tiempo, errores en límites y degradación de rendimiento.