TIMESTAMPADD
La funcion TIMESTAMPADD suma un intervalo expresado en una unidad específica a un valor de fecha o datetime. Es la contrapartida natural de TIMESTAMPDIFF: mientras que TIMESTAMPDIFF mide cuántas unidades separan dos fechas, TIMESTAMPADD avanza (o retrocede) una fecha la cantidad de unidades que indiques.
Sintaxis
TIMESTAMPADD(unidad, intervalo, datetime)El primer argumento es la unidad del intervalo. Las unidades válidas son SECOND, MINUTE, HOUR, DAY, WEEK, MONTH, QUARTER y YEAR. El segundo argumento es un número entero que indica cuántas unidades sumar (puede ser negativo para restar). El tercer argumento es el valor DATE o DATETIME al que se aplica la operación.
Comportamiento básico
Sumar 15 días a una fecha:
SELECT TIMESTAMPADD(DAY, 15, '2026-03-01') AS resultado;| resultado |
|---|
| 2026-03-16 |
La sintaxis es directa: unidad, cantidad, fecha. Para sumar meses, años o cualquier otra unidad, simplemente cambias el primer argumento:
SELECT
TIMESTAMPADD(MONTH, 3, '2026-01-15') AS mas_3_meses,
TIMESTAMPADD(YEAR, 2, '2026-01-15') AS mas_2_anios,
TIMESTAMPADD(QUARTER, 1, '2026-01-15') AS mas_1_trimestre;| mas_3_meses | mas_2_anios | mas_1_trimestre |
|---|---|---|
| 2026-04-15 | 2028-01-15 | 2026-04-15 |
Al sumar meses, TIMESTAMPADD ajusta el día cuando el mes destino tiene menos días que el mes origen, igual que DATE_ADD:
SELECT TIMESTAMPADD(MONTH, 1, '2026-01-31') AS resultado;| resultado |
|---|
| 2026-02-28 |
Enero tiene 31 días pero febrero solo 28, así que MySQL ajusta al último día válido del mes.
Para sumar horas, minutos o segundos, el argumento de entrada debería incluir el componente horario:
SELECT
TIMESTAMPADD(HOUR, 5, '2026-03-15 10:00:00') AS mas_5_horas,
TIMESTAMPADD(MINUTE, 90, '2026-03-15 10:00:00') AS mas_90_min,
TIMESTAMPADD(SECOND, 3600, '2026-03-15 10:00:00') AS mas_3600_seg;| mas_5_horas | mas_90_min | mas_3600_seg |
|---|---|---|
| 2026-03-15 15:00:00 | 2026-03-15 11:30:00 | 2026-03-15 11:00:00 |
Observa que sumar 90 minutos y sumar 3600 segundos (1 hora) producen resultados correctos, cruzando los límites de hora cuando es necesario.
Diferencia con DATE_ADD
TIMESTAMPADD y DATE_ADD logran el mismo resultado en la mayoría de los casos, pero tienen diferencias de sintaxis y estilo que vale la pena entender:
SELECT
DATE_ADD('2026-03-15', INTERVAL 6 MONTH) AS con_date_add,
TIMESTAMPADD(MONTH, 6, '2026-03-15') AS con_timestampadd;| con_date_add | con_timestampadd |
|---|---|
| 2026-09-15 | 2026-09-15 |
El resultado es idéntico. Las diferencias principales son estas: DATE_ADD usa la sintaxis INTERVAL expr unidad y admite intervalos compuestos como DAY_HOUR o YEAR_MONTH, que TIMESTAMPADD no soporta. Por otro lado, TIMESTAMPADD tiene una sintaxis funcional pura con tres argumentos separados por comas, lo que puede ser más fácil de construir dinámicamente en código de aplicación.
En general, usa DATE_ADD cuando trabajes directamente en SQL y necesites intervalos compuestos o la sintaxis + INTERVAL. Usa TIMESTAMPADD cuando necesites simetría con TIMESTAMPDIFF o cuando la sintaxis funcional encaje mejor en tu código.
Restar tiempo con valores negativos
Un valor negativo en el segundo argumento convierte la suma en una resta:
SELECT
TIMESTAMPADD(DAY, -10, '2026-03-15') AS menos_10_dias,
TIMESTAMPADD(MONTH, -3, '2026-06-15') AS menos_3_meses,
TIMESTAMPADD(HOUR, -8, '2026-03-15 20:00:00') AS menos_8_horas;| menos_10_dias | menos_3_meses | menos_8_horas |
|---|---|---|
| 2026-03-05 | 2026-03-15 | 2026-03-15 12:00:00 |
Esto hace que TIMESTAMPADD sea una función bidireccional: con un solo conocimiento de la función puedes tanto avanzar como retroceder en el tiempo.
Caso práctico: programación de tareas recurrentes
En un sistema de gestión de tareas, cada tarea tiene una frecuencia de recurrencia expresada en unidad y cantidad. TIMESTAMPADD permite calcular la próxima ejecución de forma genérica:
SELECT
t.nombre_tarea,
t.ultima_ejecucion,
t.frecuencia_valor,
t.frecuencia_unidad,
CASE t.frecuencia_unidad
WHEN 'HOUR' THEN TIMESTAMPADD(HOUR, t.frecuencia_valor, t.ultima_ejecucion)
WHEN 'DAY' THEN TIMESTAMPADD(DAY, t.frecuencia_valor, t.ultima_ejecucion)
WHEN 'WEEK' THEN TIMESTAMPADD(WEEK, t.frecuencia_valor, t.ultima_ejecucion)
WHEN 'MONTH' THEN TIMESTAMPADD(MONTH, t.frecuencia_valor, t.ultima_ejecucion)
END AS proxima_ejecucion
FROM tareas_programadas t
WHERE t.activa = 1
ORDER BY proxima_ejecucion;| nombre_tarea | ultima_ejecucion | frecuencia_valor | frecuencia_unidad | proxima_ejecucion |
|---|---|---|---|---|
| Backup incremental | 2026-02-14 02:00:00 | 6 | HOUR | 2026-02-14 08:00:00 |
| Reporte diario | 2026-02-14 08:00:00 | 1 | DAY | 2026-02-15 08:00:00 |
| Limpieza logs | 2026-02-10 03:00:00 | 1 | WEEK | 2026-02-17 03:00:00 |
| Facturación | 2026-01-15 00:00:00 | 1 | MONTH | 2026-02-15 00:00:00 |
El CASE selecciona la unidad dinámicamente según lo configurado en cada tarea. Este patrón es la base de cualquier sistema de scheduling basado en base de datos.
Caso práctico: generar series de fechas
TIMESTAMPADD es esencial para generar secuencias de fechas cuando necesitas crear un calendario o llenar huecos en reportes temporales. Combinada con una tabla de números auxiliar:
SELECT
TIMESTAMPADD(DAY, n.num, '2026-02-01') AS fecha
FROM (
SELECT 0 AS num UNION SELECT 1 UNION SELECT 2 UNION SELECT 3
UNION SELECT 4 UNION SELECT 5 UNION SELECT 6
) n
ORDER BY fecha;| fecha |
|---|
| 2026-02-01 |
| 2026-02-02 |
| 2026-02-03 |
| 2026-02-04 |
| 2026-02-05 |
| 2026-02-06 |
| 2026-02-07 |
Esta técnica se utiliza frecuentemente en un LEFT JOIN contra una tabla de hechos para garantizar que los reportes incluyan todos los días del periodo, incluso aquellos sin datos:
SELECT
calendario.fecha,
COALESCE(SUM(p.total), 0) AS ventas_dia
FROM (
SELECT TIMESTAMPADD(DAY, n.num, '2026-02-01') AS fecha
FROM (SELECT 0 AS num UNION SELECT 1 UNION SELECT 2 UNION SELECT 3
UNION SELECT 4 UNION SELECT 5 UNION SELECT 6) n
) calendario
LEFT JOIN pedidos p ON DATE(p.fecha_creacion) = calendario.fecha
GROUP BY calendario.fecha
ORDER BY calendario.fecha;| fecha | ventas_dia |
|---|---|
| 2026-02-01 | 1250.00 |
| 2026-02-02 | 0.00 |
| 2026-02-03 | 875.50 |
| 2026-02-04 | 2100.00 |
| 2026-02-05 | 450.00 |
| 2026-02-06 | 0.00 |
| 2026-02-07 | 1890.75 |
Sin la serie generada, los días sin ventas no aparecerían en el resultado. TIMESTAMPADD permite construir el esqueleto temporal completo.
Caso práctico: cálculo de fechas de vencimiento con gracia
Muchos sistemas aplican un periodo de gracia después del vencimiento. Puedes encadenar llamadas a TIMESTAMPADD para calcular ambas fechas:
SELECT
c.nombre,
f.numero_factura,
f.fecha_emision,
TIMESTAMPADD(DAY, 30, f.fecha_emision) AS fecha_vencimiento,
TIMESTAMPADD(DAY, 45, f.fecha_emision) AS fin_periodo_gracia
FROM facturas f
JOIN clientes c ON f.cliente_id = c.id
WHERE f.pagada = 0
ORDER BY f.fecha_emision
LIMIT 4;| nombre | numero_factura | fecha_emision | fecha_vencimiento | fin_periodo_gracia |
|---|---|---|---|---|
| Empresa ABC | F-2026-0089 | 2026-01-05 | 2026-02-04 | 2026-02-19 |
| Corp XYZ | F-2026-0102 | 2026-01-15 | 2026-02-14 | 2026-03-01 |
| Servicios JKL | F-2026-0118 | 2026-01-25 | 2026-02-24 | 2026-03-11 |
| Tech MNO | F-2026-0134 | 2026-02-01 | 2026-03-03 | 2026-03-18 |
Manejo de NULL
Si el valor datetime o el intervalo es NULL, TIMESTAMPADD devuelve NULL:
SELECT
TIMESTAMPADD(DAY, 5, NULL) AS fecha_nula,
TIMESTAMPADD(DAY, NULL, '2026-03-15') AS intervalo_nulo;| fecha_nula | intervalo_nulo |
|---|---|
| NULL | NULL |
Para proteger tus consultas, utiliza COALESCE o IFNULL según el contexto:
SELECT
nombre,
TIMESTAMPADD(MONTH, 12,
COALESCE(fecha_ultimo_contrato, fecha_registro)
) AS fecha_revision
FROM clientes;Combinación con otras funciones
TIMESTAMPADD funciona bien junto a TIMESTAMPDIFF para crear lógica de ida y vuelta temporal. Por ejemplo, calcular cuántos meses de antigüedad tiene un cliente y luego proyectar cuándo alcanzará el siguiente nivel:
SELECT
c.nombre,
c.fecha_registro,
TIMESTAMPDIFF(MONTH, c.fecha_registro, CURDATE()) AS meses_antiguedad,
CASE
WHEN TIMESTAMPDIFF(MONTH, c.fecha_registro, CURDATE()) < 12
THEN TIMESTAMPADD(MONTH, 12, c.fecha_registro)
WHEN TIMESTAMPDIFF(MONTH, c.fecha_registro, CURDATE()) < 24
THEN TIMESTAMPADD(MONTH, 24, c.fecha_registro)
ELSE NULL
END AS fecha_proximo_nivel
FROM clientes c
WHERE c.activo = 1
ORDER BY meses_antiguedad DESC
LIMIT 4;| nombre | fecha_registro | meses_antiguedad | fecha_proximo_nivel |
|---|---|---|---|
| María García | 2023-05-10 | 33 | NULL |
| Carlos López | 2024-08-20 | 17 | 2026-08-20 |
| Ana Martínez | 2025-06-01 | 8 | 2026-06-01 |
| Pedro Ruiz | 2025-11-15 | 2 | 2026-11-15 |
Los clientes con más de 24 meses ya alcanzaron el nivel máximo (resultado NULL), mientras que los demás ven proyectada la fecha en la que subirán de nivel.
En el siguiente artículo veremos EXTRACT para extraer partes específicas de una fecha.
Escrito por Eduardo Lázaro
