TO_DAYS

La función TO_DAYS convierte una fecha en un número entero que representa la cantidad total de días desde el año 0. Este número es el "contador de días absoluto" interno de MySQL y es la operación inversa de FROM_DAYS. Mientras que funciones como DATEDIFF calculan la diferencia entre dos fechas, TO_DAYS te da un valor numérico único para cada fecha, lo que permite hacer aritmética de fechas usando operaciones matemáticas simples.

En la práctica, TO_DAYS es una alternativa a DATEDIFF para calcular diferencias de días, y una herramienta útil para indexar fechas numéricamente, particionar datos por rangos de fechas o realizar cálculos de calendario que requieren manipulación numérica directa.

Sintaxis

TO_DAYS(fecha)

El argumento es cualquier expresión que MySQL pueda interpretar como fecha o datetime. La función devuelve un entero grande (típicamente en el rango de 730000-740000 para fechas contemporáneas). Al igual que FROM_DAYS, los resultados solo son fiables para fechas a partir del año 1582, cuando se adoptó el calendario gregoriano.

Comportamiento básico

Veamos qué números de día devuelve TO_DAYS para algunas fechas conocidas:

SELECT
    TO_DAYS('2025-01-01') AS inicio_2025,
    TO_DAYS('2025-06-15') AS mediados_2025,
    TO_DAYS('2025-12-31') AS fin_2025,
    TO_DAYS('1970-01-01') AS epoca_unix;
inicio_2025mediados_2025fin_2025epoca_unix
738886739051739250719528

Cada fecha tiene un número único. El 1 de enero de 2025 es el día 738886, y el 31 de diciembre de 2025 es el día 739250. La diferencia (739250 - 738886 = 364) nos dice que hay 364 días entre esas dos fechas, lo que es correcto: del 1 de enero al 31 de diciembre hay 364 días (o 365 si incluimos ambos extremos).

Calcular diferencias de días

La forma más directa de usar TO_DAYS es restar dos valores para obtener la diferencia en días, como alternativa a DATEDIFF:

SELECT
    TO_DAYS('2025-12-31') - TO_DAYS('2025-01-01') AS dias_datediff,
    DATEDIFF('2025-12-31', '2025-01-01') AS con_datediff;
dias_datediffcon_datediff
364364

Ambos métodos dan el mismo resultado. La ventaja de DATEDIFF es su legibilidad; la ventaja de TO_DAYS es que el valor numérico puede almacenarse, indexarse y usarse en cálculos más complejos.

Caso práctico: calcular antigüedad de clientes

Un uso habitual de TO_DAYS es calcular cuántos días lleva un cliente registrado, lo que puede usarse para segmentación o programas de fidelidad:

SELECT
    nombre,
    fecha_registro,
    TO_DAYS(CURDATE()) - TO_DAYS(fecha_registro) AS dias_como_cliente,
    FLOOR((TO_DAYS(CURDATE()) - TO_DAYS(fecha_registro)) / 365) AS anios_aprox
FROM clientes
ORDER BY dias_como_cliente DESC
LIMIT 5;
nombrefecha_registrodias_como_clienteanios_aprox
Elena Martínez2019-03-1522896
Roberto Sánchez2020-01-1019885
Ana Torres2020-08-2217644
Miguel Fernández2021-05-0315104
Laura Gómez2022-02-1412223

La división entre 365 da una aproximación de años (sin considerar bisiestos, pero suficiente para segmentación general). Para cálculos más precisos, TIMESTAMPDIFF(YEAR, ...) sería más adecuado, pero TO_DAYS te permite trabajar con el valor numérico bruto para cálculos personalizados.

Caso práctico: particionar datos por rangos de fechas

Cuando trabajas con tablas grandes, a veces necesitas dividir los datos en bloques basados en rangos de fechas. TO_DAYS facilita esta operación al convertir las fechas en números que puedes comparar directamente:

SELECT
    CASE
        WHEN TO_DAYS(fecha) BETWEEN TO_DAYS('2025-01-01') AND TO_DAYS('2025-03-31') THEN 'Q1-2025'
        WHEN TO_DAYS(fecha) BETWEEN TO_DAYS('2025-04-01') AND TO_DAYS('2025-06-30') THEN 'Q2-2025'
        WHEN TO_DAYS(fecha) BETWEEN TO_DAYS('2025-07-01') AND TO_DAYS('2025-09-30') THEN 'Q3-2025'
        WHEN TO_DAYS(fecha) BETWEEN TO_DAYS('2025-10-01') AND TO_DAYS('2025-12-31') THEN 'Q4-2025'
    END AS trimestre,
    COUNT(*) AS total_pedidos,
    SUM(total) AS ingresos
FROM pedidos
WHERE YEAR(fecha) = 2025
GROUP BY trimestre
ORDER BY trimestre;
trimestretotal_pedidosingresos
Q1-20251005259800.25
Q2-20251128291450.50
Q3-2025987255120.00
Q4-20251064275890.75

Aunque en este ejemplo podrías usar QUARTER() directamente, el enfoque con TO_DAYS es más flexible porque permite definir rangos arbitrarios que no coincidan con trimestres naturales, como períodos fiscales, campañas de marketing o temporadas de ventas.

Caso práctico: agrupar en bloques de N días

Una aplicación poderosa de TO_DAYS es agrupar datos en bloques de un número arbitrario de días. Por ejemplo, para analizar ventas en bloques de 7 días (semanas) o 14 días (quincenas):

SELECT
    FROM_DAYS(MIN(TO_DAYS(fecha))) AS inicio_bloque,
    FROM_DAYS(MAX(TO_DAYS(fecha))) AS fin_bloque,
    COUNT(*) AS pedidos,
    ROUND(SUM(total), 2) AS ingresos
FROM pedidos
WHERE fecha BETWEEN '2025-01-01' AND '2025-02-28'
GROUP BY FLOOR(TO_DAYS(fecha) / 14)
ORDER BY inicio_bloque;
inicio_bloquefin_bloquepedidosingresos
2025-01-012025-01-1315640320.50
2025-01-142025-01-2716843480.00
2025-01-282025-02-1014236750.25
2025-02-112025-02-2415941120.75
2025-02-252025-02-284812430.00

La clave es FLOOR(TO_DAYS(fecha) / 14): divide el número de día entre 14 y redondea hacia abajo, lo que agrupa todas las fechas dentro del mismo bloque de 14 días. Puedes cambiar el 14 por cualquier número para crear bloques de la duración que necesites.

La advertencia del calendario gregoriano

Al igual que FROM_DAYS, TO_DAYS no produce resultados históricamente correctos para fechas anteriores al 15 de octubre de 1582, cuando entró en vigor el calendario gregoriano. MySQL usa el calendario gregoriano proléptico (lo extiende hacia atrás), lo que no coincide con el calendario juliano que se usaba realmente en esas épocas:

SELECT
    TO_DAYS('1582-10-15') AS gregoriana,
    TO_DAYS('1582-10-04') AS pre_gregoriana,
    TO_DAYS('0001-01-01') AS año_uno;
gregorianapre_gregorianaaño_uno
577738577727366

Para aplicaciones empresariales modernas, esta limitación es irrelevante. Solo importa si trabajas con datos históricos anteriores al siglo XVI.

TO_DAYS con NULL

Si la fecha es NULL o inválida, TO_DAYS devuelve NULL:

SELECT
    TO_DAYS(NULL) AS nulo,
    TO_DAYS('2025-00-00') AS fecha_invalida;
nulofecha_invalida
NULLNULL

Combinación con otras funciones

TO_DAYS se combina de forma natural con FROM_DAYS para hacer ida y vuelta entre fechas y números. Un ejemplo práctico es calcular el día de la semana sin usar DAYOFWEEK, aprovechando que los días de la semana se repiten cada 7 días:

SELECT
    fecha,
    DAYNAME(fecha) AS nombre_dia,
    TO_DAYS(fecha) % 7 AS residuo_mod7
FROM (
    SELECT '2025-06-16' AS fecha
    UNION SELECT '2025-06-17'
    UNION SELECT '2025-06-18'
    UNION SELECT '2025-06-19'
    UNION SELECT '2025-06-20'
    UNION SELECT '2025-06-21'
    UNION SELECT '2025-06-22'
) dias;
fechanombre_diaresiduo_mod7
2025-06-16Monday0
2025-06-17Tuesday1
2025-06-18Wednesday2
2025-06-19Thursday3
2025-06-20Friday4
2025-06-21Saturday5
2025-06-22Sunday6

El residuo de TO_DAYS dividido entre 7 produce un número cíclico que corresponde al día de la semana. Aunque DAYOFWEEK o WEEKDAY son más directos para este propósito, este ejemplo ilustra la versatilidad de TO_DAYS para cálculos modulares con fechas.

En el siguiente artículo veremos FROM_UNIXTIME para convertir timestamps Unix a fechas legibles.

Escrito por Eduardo Lázaro