DATEDIFF devuelve el número de días, meses u otras unidades entre dos fechas. Cada base de datos lo hace de forma distinta, y los ejemplos cubren PostgreSQL, MySQL, SQLite y SQL Server.
Cómo usar DATEDIFF
DATEDIFF cuenta los días, meses, años u otras unidades desde una fecha de inicio hasta una fecha de fin. Esta es la versión de SQL Server, la que la mayoría tiene en mente:
DATEDIFF(unit, start_date, end_date)
SELECT DATEDIFF(day, '2026-01-01', '2026-03-15');
-- Output: 73
SELECT DATEDIFF(month, '2026-01-01', '2026-03-15');
-- Output: 2
SELECT DATEDIFF(day, '2026-03-15', '2026-01-01');
-- Output: -73
La unidad puede ser year, quarter, month, week, day, hour, minute, second o más pequeña. Si la fecha de fin es anterior a la de inicio, el resultado es negativo.
Con columnas, obtienes una diferencia por fila:
-- Input: orders
-- order_id | order_date | ship_date
-- ---------+------------+-----------
-- 1001 | 2026-02-02 | 2026-02-04
-- 1002 | 2026-02-03 | 2026-02-10
-- 1003 | 2026-02-27 | 2026-03-02
-- 1004 | 2026-03-05 | NULL
SELECT
order_id,
order_date,
ship_date,
DATEDIFF(day, order_date, ship_date) AS fulfillment_days
FROM orders;
-- Output:
-- order_id | order_date | ship_date | fulfillment_days
-- ---------+------------+------------+-----------------
-- 1001 | 2026-02-02 | 2026-02-04 | 2
-- 1002 | 2026-02-03 | 2026-02-10 | 7
-- 1003 | 2026-02-27 | 2026-03-02 | 3
-- 1004 | 2026-03-05 | NULL | NULL
Reglas que debes conocer
-
Cuenta límites, no unidades completas.
DATEDIFF(month, ...)cuenta los cambios de mes entre las dos fechas, así que un solo día puede contar como un mes, o como un año:
SELECT DATEDIFF(month, '2026-01-31', '2026-02-01');
-- Output: 1
SELECT DATEDIFF(year, '2025-12-31', '2026-01-01');
-- Output: 1
-
Si entra NULL, sale NULL. Si cualquiera de las fechas es NULL, el resultado también lo es, como en el pedido 1004 de arriba. Envuelve la llamada en
COALESCE()cuando necesites un valor predeterminado.
Sintaxis alternativa
MySQL tiene un DATEDIFF de dos argumentos que solo cuenta días y recibe primero la fecha de fin. Para cualquier otra unidad, usa TIMESTAMPDIFF, que recibe primero la fecha de inicio y cuenta unidades completas:
SELECT DATEDIFF('2026-03-15', '2026-01-01');
-- Output: 73
SELECT TIMESTAMPDIFF(MONTH, '2026-01-01', '2026-03-15');
-- Output: 2
PostgreSQL no tiene DATEDIFF. Resta una fecha de otra para obtener los días. Para unidades más grandes, AGE() (con la fecha más reciente primero) devuelve un intervalo en años, meses y días, y EXTRACT saca de él las unidades completas:
SELECT DATE '2026-03-15' - DATE '2026-01-01';
-- Output: 73
SELECT AGE('2026-03-15', '2026-01-01');
-- Output: 2 mons 14 days
SELECT EXTRACT(YEAR FROM AGE('2026-03-15', '2026-01-01')) * 12
+ EXTRACT(MONTH FROM AGE('2026-03-15', '2026-01-01'));
-- Output: 2
SQLite tampoco tiene DATEDIFF. julianday() convierte una fecha en un número de días, así que al restar dos obtienes la diferencia. CAST(... AS INTEGER) elimina la parte decimal, y como no hay unidad de mes ni de año, divide entre 30 o 365 para obtener una aproximación:
SELECT julianday('2026-03-15') - julianday('2026-01-01');
-- Output: 73.0
SELECT CAST((julianday('2026-03-15') - julianday('2026-01-01')) / 30 AS INTEGER);
-- Output: 2
-- The time of day counts: 8 p.m. to 8 a.m. is half a day.
-- Wrap each value in date() to count calendar days instead.
SELECT julianday('2026-03-16 08:00') - julianday('2026-03-15 20:00');
-- Output: 0.5
-- A date it can't read gives NULL, so store dates as YYYY-MM-DD
SELECT julianday('03/15/2026');
-- Output: NULL
¿Cuándo deberías usar DATEDIFF?
La mayoría de las preguntas sobre diferencias de fechas entran en uno de estos cuatro casos.
Medir cuánto tardó algo
Resta una fecha de inicio de una fecha de fin para obtener una duración: los días que tardó en enviarse un pedido, las semanas que duró un proyecto, los minutos que duró una llamada de soporte.
Contar días de retraso o restantes
Compara una fecha límite con hoy, o con una fecha de reporte fija, para ver qué tan atrasado va algo o cuánto tiempo queda. Filtra según el signo del resultado para quedarte con un lado.
Expresar una antigüedad en meses o años
La antigüedad de una cuenta, el tiempo como cliente o los años de servicio necesitan una unidad mayor que los días. Usa una unidad de mes o año si tu base de datos la tiene. En SQLite, divide los días.
Encontrar filas dentro de un rango alrededor de una fecha
Toma el valor absoluto de la diferencia para encontrar filas a cierta cantidad de días de una fecha, antes o después: eventos cerca de un lanzamiento, inicios de sesión alrededor de un incidente.
Ejemplos reales de DATEDIFF
Revisar tickets de soporte contra un SLA
Cada ticket debe resolverse en un máximo de tres días. Cuenta los días que tardó cada uno y marca los incumplimientos (SQLite):
-- Input: support_tickets
-- ticket_id | created_at | resolved_at
-- ----------+------------+------------
-- 301 | 2026-03-02 | 2026-03-03
-- 302 | 2026-03-04 | 2026-03-07
-- 303 | 2026-03-05 | 2026-03-10
SELECT
ticket_id,
created_at,
resolved_at,
CAST(julianday(resolved_at) - julianday(created_at) AS INTEGER) AS resolution_days,
CASE
WHEN julianday(resolved_at) - julianday(created_at) <= 3 THEN 'Within SLA'
ELSE 'SLA Breach'
END AS sla_status
FROM support_tickets;
-- Output:
-- ticket_id | created_at | resolved_at | resolution_days | sla_status
-- ----------+------------+-------------+-----------------+-----------
-- 301 | 2026-03-02 | 2026-03-03 | 1 | Within SLA
-- 302 | 2026-03-04 | 2026-03-07 | 3 | Within SLA
-- 303 | 2026-03-05 | 2026-03-10 | 5 | SLA Breach
Listar facturas vencidas
Muestra las facturas que ya pasaron su fecha de vencimiento, empezando por las más atrasadas (MySQL):
-- Input: invoices
-- invoice_id | customer | due_date
-- -----------+---------------+-----------
-- 5001 | Acme Hardware | 2026-08-15
-- 5002 | Lumen Design | 2026-09-30
-- 5003 | Acme Hardware | 2026-10-01
-- 5004 | Cedar Clinic | 2026-10-31
SELECT
invoice_id,
customer,
due_date,
DATEDIFF(CURDATE(), due_date) AS days_overdue
FROM invoices
WHERE due_date < CURDATE()
ORDER BY days_overdue DESC;
-- Output (run on 2026-10-13):
-- invoice_id | customer | due_date | days_overdue
-- -----------+---------------+------------+-------------
-- 5001 | Acme Hardware | 2026-08-15 | 59
-- 5002 | Lumen Design | 2026-09-30 | 13
-- 5003 | Acme Hardware | 2026-10-01 | 12
Agrupar clientes por cuánto tiempo llevan contigo
Clasifica a los clientes en niveles según su antigüedad en años completos (PostgreSQL):
-- Input: customers
-- customer_name | signup_date
-- ------------------+------------
-- Northwind Traders | 2022-11-05
-- Bluebird Bakery | 2025-06-20
-- Fjord Outfitters | 2025-12-20
-- Kestrel Labs | 2026-03-02
SELECT
customer_name,
signup_date,
EXTRACT(YEAR FROM AGE(CURRENT_DATE, signup_date)) AS years_with_us,
CASE
WHEN AGE(CURRENT_DATE, signup_date) < INTERVAL '1 year' THEN 'New'
WHEN AGE(CURRENT_DATE, signup_date) < INTERVAL '2 years' THEN 'Established'
ELSE 'Loyal'
END AS customer_tier
FROM customers;
-- Output (run on 2026-10-13):
-- customer_name | signup_date | years_with_us | customer_tier
-- ------------------+-------------+---------------+--------------
-- Northwind Traders | 2022-11-05 | 3 | Loyal
-- Bluebird Bakery | 2025-06-20 | 1 | Established
-- Fjord Outfitters | 2025-12-20 | 0 | New
-- Kestrel Labs | 2026-03-02 | 0 | New
Encontrar suscripciones por renovar
Lista las suscripciones que terminan en los próximos 30 días, con los días restantes (SQL Server). La cláusula WHERE compara subscription_end con un rango de fechas en lugar de envolverla en DATEDIFF, para que se pueda seguir usando un índice sobre la columna.
-- Input: subscriptions
-- customer_name | subscription_end
-- -----------------+-----------------
-- Harbor Dental | 2026-10-09
-- Maple Yoga | 2026-10-20
-- Orbit Analytics | 2026-11-07
-- Pinecrest Realty | 2027-01-15
SELECT
customer_name,
subscription_end,
DATEDIFF(day, GETDATE(), subscription_end) AS days_remaining
FROM subscriptions
WHERE subscription_end BETWEEN CAST(GETDATE() AS date)
AND DATEADD(day, 30, CAST(GETDATE() AS date))
ORDER BY days_remaining;
-- Output (run on 2026-10-13):
-- customer_name | subscription_end | days_remaining
-- ----------------+------------------+---------------
-- Maple Yoga | 2026-10-20 | 7
-- Orbit Analytics | 2026-11-07 | 25
Más lecturas sobre DATEDIFF
En este blog:
-
Guía de formato de fechas en SQL: cómo convertir fechas en texto con
strftime,TO_CHAR,DATE_FORMATyFORMAT - Guía para insertar fechas en SQL: tipos de fecha y cómo insertar valores de fecha
- Cómo restar en SQL: resta de números, fechas y timestamps
-
Cómo restar en PostgreSQL: aritmética de fechas y timestamps, incluido
age() -
Operaciones de resta en SQLite: diferencias de fechas con
julianday() - Extraer el total de días, horas o minutos de un intervalo en PostgreSQL: cómo convertir intervalos en números
- Guía de COALESCE en SQL: valores predeterminados para fechas NULL
Documentación oficial:
- PostgreSQL: funciones y operadores de fecha/hora
- MySQL: DATEDIFF() y TIMESTAMPDIFF()
- SQLite: funciones de fecha y hora
- SQL Server: DATEDIFF
Beekeeper Studio es un cliente de bases de datos gratuito y de código abierto
La mejor herramienta de consultas y edición de SQL que he usado. Tiene todo lo que necesito para administrar mi base de datos. - ⭐⭐⭐⭐⭐ Mit
Beekeeper Studio es rápido, intuitivo y fácil de usar. Es compatible con muchísimas bases de datos y funciona de maravilla en Windows, Mac y Linux.
Lo que dicen los usuarios de Beekeeper Studio
"Beekeeper Studio reemplazó por completo mi antiguo flujo de trabajo con SQL. Es rápido, intuitivo y hace que trabajar con bases de datos vuelva a ser agradable."
"He probado muchas GUI de bases de datos, pero Beekeeper logra el equilibrio perfecto entre funciones y simplicidad. Simplemente funciona."