DATEDIFF
La funcion DATEDIFF calcula la diferencia en días entre dos fechas. Devuelve un número entero que representa cuántos días separan la primera fecha de la segunda. Es la función más directa de MySQL para responder preguntas como "cuántos días han pasado desde..." o "cuántos días faltan para...".
Sintaxis
DATEDIFF(fecha1, fecha2)Ambos argumentos deben ser valores de tipo DATE o DATETIME. Si pasas valores DATETIME, MySQL utiliza únicamente la parte de la fecha para el cálculo, ignorando por completo el componente horario. El resultado es fecha1 - fecha2 expresado en días.
Comportamiento básico
Calcular los días entre dos fechas concretas:
SELECT DATEDIFF('2026-03-25', '2026-03-15') AS diferencia;| diferencia |
|---|
| 10 |
El resultado es 10 porque hay 10 días entre el 15 y el 25 de marzo. El orden de los argumentos importa: DATEDIFF calcula fecha1 - fecha2. Si inviertes el orden, el resultado cambia de signo:
SELECT
DATEDIFF('2026-03-25', '2026-03-15') AS positivo,
DATEDIFF('2026-03-15', '2026-03-25') AS negativo;| positivo | negativo |
|---|---|
| 10 | -10 |
Un resultado positivo indica que fecha1 es posterior a fecha2. Un resultado negativo indica lo contrario. Esta propiedad es fundamental para entender los resultados de DATEDIFF: siempre piensa en ello como "primera fecha menos segunda fecha".
Cuando los argumentos son valores DATETIME, el componente horario se descarta:
SELECT DATEDIFF('2026-03-15 23:59:59', '2026-03-15 00:00:01') AS diferencia;| diferencia |
|---|
| 0 |
Aunque hay casi 24 horas de diferencia, DATEDIFF solo compara las fechas (ambas son 15 de marzo) y devuelve 0. Si necesitas precisión horaria, deberás usar TIMEDIFF o TIMESTAMPDIFF.
Caso práctico: antigüedad de pedidos
Un uso muy frecuente es calcular cuántos días han transcurrido desde que se creó un pedido. Esto permite identificar pedidos estancados o medir tiempos de procesamiento:
SELECT
id,
cliente_id,
estado,
fecha_creacion,
DATEDIFF(CURDATE(), fecha_creacion) AS dias_desde_creacion
FROM pedidos
WHERE estado != 'entregado'
ORDER BY dias_desde_creacion DESC
LIMIT 5;| id | cliente_id | estado | fecha_creacion | dias_desde_creacion |
|---|---|---|---|---|
| 892 | 156 | pendiente | 2025-12-20 | 56 |
| 945 | 89 | en_proceso | 2026-01-05 | 40 |
| 978 | 234 | en_proceso | 2026-01-15 | 30 |
| 1001 | 67 | enviado | 2026-01-28 | 17 |
| 1015 | 312 | enviado | 2026-02-03 | 11 |
Al usar CURDATE() como primer argumento, el resultado siempre refleja los días transcurridos hasta hoy. Un pedido pendiente desde hace 56 días seguramente requiere atención inmediata.
Caso práctico: días hasta vencimiento
Invertir el orden de los argumentos permite calcular cuántos días faltan para una fecha futura, como la expiración de una membresía:
SELECT
c.nombre,
m.tipo_plan,
m.fecha_vencimiento,
DATEDIFF(m.fecha_vencimiento, CURDATE()) AS dias_restantes,
CASE
WHEN DATEDIFF(m.fecha_vencimiento, CURDATE()) < 0 THEN 'Vencida'
WHEN DATEDIFF(m.fecha_vencimiento, CURDATE()) <= 7 THEN 'Por vencer'
ELSE 'Vigente'
END AS estado
FROM membresias m
JOIN clientes c ON m.cliente_id = c.id
ORDER BY dias_restantes
LIMIT 6;| nombre | tipo_plan | fecha_vencimiento | dias_restantes | estado |
|---|---|---|---|---|
| Roberto Díaz | mensual | 2026-02-10 | -4 | Vencida |
| Elena Ruiz | mensual | 2026-02-12 | -2 | Vencida |
| Carlos López | trimestral | 2026-02-16 | 2 | Por vencer |
| Ana Martínez | mensual | 2026-02-20 | 6 | Por vencer |
| Pedro Navarro | anual | 2026-05-30 | 105 | Vigente |
| Lucía Fernández | anual | 2026-08-15 | 182 | Vigente |
El valor negativo en dias_restantes indica que la membresía ya venció. La combinación de DATEDIFF con CASE permite clasificar automáticamente el estado de cada registro.
Caso práctico: tiempo de entrega promedio
DATEDIFF combinada con funciones de agregación permite calcular métricas de rendimiento operativo. Por ejemplo, el tiempo promedio de entrega por categoría de producto:
SELECT
cat.nombre AS categoria,
COUNT(p.id) AS total_pedidos,
ROUND(AVG(DATEDIFF(p.fecha_entrega, p.fecha_creacion)), 1) AS promedio_dias_entrega,
MIN(DATEDIFF(p.fecha_entrega, p.fecha_creacion)) AS minimo,
MAX(DATEDIFF(p.fecha_entrega, p.fecha_creacion)) AS maximo
FROM pedidos p
JOIN productos prod ON p.producto_id = prod.id
JOIN categorias cat ON prod.categoria_id = cat.id
WHERE p.fecha_entrega IS NOT NULL
GROUP BY cat.nombre
ORDER BY promedio_dias_entrega;| categoria | total_pedidos | promedio_dias_entrega | minimo | maximo |
|---|---|---|---|---|
| Libros | 245 | 2.3 | 1 | 5 |
| Electrónica | 512 | 3.8 | 1 | 12 |
| Ropa | 389 | 4.1 | 2 | 10 |
| Hogar | 178 | 5.7 | 2 | 15 |
| Deportes | 134 | 6.2 | 3 | 18 |
AVG(DATEDIFF(...)) calcula el promedio de los días de entrega para cada grupo, mientras que MIN y MAX muestran el rango. Este tipo de análisis es esencial para evaluar la eficiencia logística.
Caso práctico: agrupar por ventanas temporales
Puedes usar DATEDIFF para segmentar registros en rangos de días, lo que es útil para análisis de cohortes o clasificación de deudas:
SELECT
CASE
WHEN DATEDIFF(CURDATE(), fecha_factura) <= 30 THEN '0-30 días'
WHEN DATEDIFF(CURDATE(), fecha_factura) <= 60 THEN '31-60 días'
WHEN DATEDIFF(CURDATE(), fecha_factura) <= 90 THEN '61-90 días'
ELSE 'Más de 90 días'
END AS antiguedad,
COUNT(*) AS cantidad,
SUM(monto_pendiente) AS total_pendiente
FROM facturas
WHERE pagada = 0
GROUP BY antiguedad
ORDER BY MIN(DATEDIFF(CURDATE(), fecha_factura));| antiguedad | cantidad | total_pendiente |
|---|---|---|
| 0-30 días | 45 | 28750.00 |
| 31-60 días | 23 | 18200.50 |
| 61-90 días | 12 | 9800.00 |
| Más de 90 días | 8 | 15600.75 |
Este patrón de segmentación por antigüedad es estándar en el análisis financiero de cuentas por cobrar.
Manejo de NULL
Si cualquiera de los argumentos es NULL, DATEDIFF devuelve NULL:
SELECT
DATEDIFF(NULL, '2026-03-15') AS primero_nulo,
DATEDIFF('2026-03-15', NULL) AS segundo_nulo;| primero_nulo | segundo_nulo |
|---|---|
| NULL | NULL |
En consultas con columnas que pueden contener NULL (como una fecha de entrega que aún no ha ocurrido), filtra los nulos o proporciona un valor alternativo:
SELECT
id,
COALESCE(
DATEDIFF(fecha_entrega, fecha_creacion),
DATEDIFF(CURDATE(), fecha_creacion)
) AS dias_transcurridos
FROM pedidos;Esta consulta usa los días hasta la entrega si la fecha de entrega existe, y si no, los días desde la creación hasta hoy.
Combinación con otras funciones
DATEDIFF se combina frecuentemente con ABS cuando no te importa el signo de la diferencia:
SELECT ABS(DATEDIFF('2026-01-10', '2026-03-15')) AS distancia_en_dias;| distancia_en_dias |
|---|
| 64 |
Para convertir la diferencia de días en semanas, meses aproximados o años aproximados, puedes hacer aritmética simple:
SELECT
DATEDIFF('2027-02-14', '2026-02-14') AS dias,
DATEDIFF('2027-02-14', '2026-02-14') / 7 AS semanas,
DATEDIFF('2027-02-14', '2026-02-14') / 30.44 AS meses_aprox,
DATEDIFF('2027-02-14', '2026-02-14') / 365.25 AS anios_aprox;| dias | semanas | meses_aprox | anios_aprox |
|---|---|---|---|
| 365 | 52.1429 | 11.9908 | 0.9993 |
Sin embargo, para obtener diferencias precisas en meses o años, la función TIMESTAMPDIFF es una opción más fiable que estas aproximaciones.
En el siguiente artículo veremos TIMEDIFF para calcular la diferencia de tiempo entre dos valores.
Escrito por Eduardo Lázaro
