MAKEDATE

La función MAKEDATE construye una fecha a partir de dos componentes: un año y el número de día dentro de ese año. Por ejemplo, el día 32 del año 2025 corresponde al 1 de febrero, porque enero tiene 31 días y el día 32 es el primero de febrero. Es la operación inversa de DAYOFYEAR: mientras DAYOFYEAR toma una fecha y devuelve el número de día del año, MAKEDATE toma el número de día del año y devuelve la fecha correspondiente.

Esta función resulta especialmente útil cuando trabajas con datos que almacenan fechas como número ordinal del año (algo común en sistemas industriales, logística y formatos de archivo heredados), o cuando necesitas generar secuencias de fechas para calendarios y reportes.

Sintaxis

MAKEDATE(año, dia_del_año)

El primer argumento es el año (cuatro dígitos) y el segundo es un número entero que representa el día del año, donde 1 es el 1 de enero. La función devuelve un valor de tipo DATE. Si el día del año es 0 o menor, devuelve NULL. Si es mayor que los días que tiene el año, la fecha se desborda al año siguiente.

Comportamiento básico

Veamos cómo MAKEDATE convierte números de día en fechas concretas:

SELECT
    MAKEDATE(2025, 1) AS primer_dia,
    MAKEDATE(2025, 31) AS fin_enero,
    MAKEDATE(2025, 32) AS inicio_febrero,
    MAKEDATE(2025, 365) AS fin_anio;
primer_diafin_eneroinicio_febrerofin_anio
2025-01-012025-01-312025-02-012025-12-31

El día 1 es siempre el 1 de enero, el día 31 es el último día de enero, el 32 es el primero de febrero, y el 365 es el 31 de diciembre en un año no bisiesto.

Años bisiestos

En un año bisiesto, el día 366 es válido y corresponde al 31 de diciembre. Además, el día 60 cambia de significado:

SELECT
    MAKEDATE(2024, 60) AS dia60_bisiesto,
    MAKEDATE(2025, 60) AS dia60_normal,
    MAKEDATE(2024, 366) AS ultimo_bisiesto;
dia60_bisiestodia60_normalultimo_bisiesto
2024-02-292025-03-012024-12-31

En 2024 (bisiesto), el día 60 es el 29 de febrero. En 2025 (no bisiesto), el día 60 es el 1 de marzo. MAKEDATE maneja esta diferencia automáticamente.

Desbordamiento de días

Si pasas un número de día mayor que los días del año, MySQL no genera un error sino que la fecha se extiende al año siguiente:

SELECT
    MAKEDATE(2025, 366) AS dia_366,
    MAKEDATE(2025, 400) AS dia_400;
dia_366dia_400
2026-01-012026-02-04

El día 366 de 2025 (que no es bisiesto) se convierte en el 1 de enero de 2026. El día 400 se convierte en el 4 de febrero de 2026. Este comportamiento puede ser útil o peligroso, dependiendo de si lo esperas o no.

Caso práctico: verificar la relación con DAYOFYEAR

MAKEDATE y DAYOFYEAR son funciones inversas. Puedes comprobarlo fácilmente:

SELECT
    fecha_original,
    DAYOFYEAR(fecha_original) AS dia_del_anio,
    MAKEDATE(YEAR(fecha_original), DAYOFYEAR(fecha_original)) AS reconstruida
FROM (
    SELECT '2025-03-15' AS fecha_original
    UNION SELECT '2025-07-04'
    UNION SELECT '2025-12-25'
) fechas;
fecha_originaldia_del_anioreconstruida
2025-03-15742025-03-15
2025-07-041852025-07-04
2025-12-253592025-12-25

En todos los casos, la fecha reconstruida coincide exactamente con la original. Esta propiedad es útil cuando necesitas convertir entre los dos formatos.

Caso práctico: generar secuencias de fechas

Uno de los usos más potentes de MAKEDATE es generar una secuencia de fechas consecutivas. Esto es invaluable para crear tablas de calendario o para cruzar con datos y detectar días sin actividad:

SELECT MAKEDATE(2025, n) AS fecha
FROM (
    SELECT 1 n UNION SELECT 2 UNION SELECT 3 UNION SELECT 4
    UNION SELECT 5 UNION SELECT 6 UNION SELECT 7
) dias
ORDER BY fecha;
fecha
2025-01-01
2025-01-02
2025-01-03
2025-01-04
2025-01-05
2025-01-06
2025-01-07

Con una tabla de números más amplia (o un CTE recursivo en MySQL 8+), puedes generar los 365 días del año completo y hacer un LEFT JOIN con tus ventas para identificar días sin pedidos:

WITH RECURSIVE dias AS (
    SELECT 1 AS n
    UNION ALL
    SELECT n + 1 FROM dias WHERE n < 365
)
SELECT
    MAKEDATE(2025, d.n) AS fecha,
    COALESCE(COUNT(p.id), 0) AS pedidos
FROM dias d
LEFT JOIN pedidos p ON DATE(p.fecha) = MAKEDATE(2025, d.n)
WHERE d.n BETWEEN 1 AND 90
GROUP BY MAKEDATE(2025, d.n)
HAVING pedidos = 0
ORDER BY fecha
LIMIT 5;
fechapedidos
2025-01-010
2025-01-060
2025-02-140
2025-03-090
2025-03-230

Este tipo de análisis permite descubrir patrones como días festivos o domingos donde la tienda no tuvo actividad.

Caso práctico: convertir datos de sistemas legacy

Algunos sistemas antiguos almacenan fechas como año y día juliano (el número ordinal del día dentro del año). Si importas datos con ese formato, MAKEDATE es la función perfecta para la conversión:

SELECT
    codigo_lote,
    anio,
    dia_juliano,
    MAKEDATE(anio, dia_juliano) AS fecha_produccion
FROM (
    SELECT 'LOT-2025-074' AS codigo_lote, 2025 AS anio, 74 AS dia_juliano
    UNION SELECT 'LOT-2025-185', 2025, 185
    UNION SELECT 'LOT-2024-366', 2024, 366
) lotes;
codigo_loteaniodia_julianofecha_produccion
LOT-2025-0742025742025-03-15
LOT-2025-18520251852025-07-04
LOT-2024-36620243662024-12-31

Este patrón es muy común al integrar datos de sistemas ERP industriales o al procesar archivos EDI que usan el formato de fecha juliana.

MAKEDATE con NULL

MAKEDATE devuelve NULL cuando el año es NULL, el día es NULL o el día es menor o igual a 0:

SELECT
    MAKEDATE(NULL, 100) AS anio_nulo,
    MAKEDATE(2025, NULL) AS dia_nulo,
    MAKEDATE(2025, 0) AS dia_cero,
    MAKEDATE(2025, -5) AS dia_negativo;
anio_nulodia_nulodia_cerodia_negativo
NULLNULLNULLNULL

Es importante recordar que el día 0 no es válido (no existe "el día cero del año"), así que siempre devuelve NULL.

Combinación con otras funciones

MAKEDATE se combina muy bien con funciones aritméticas para construir fechas relativas. Por ejemplo, para obtener el primer día de cada trimestre de un año:

SELECT
    MAKEDATE(2025, 1) AS Q1,
    MAKEDATE(2025, 1) + INTERVAL 3 MONTH AS Q2,
    MAKEDATE(2025, 1) + INTERVAL 6 MONTH AS Q3,
    MAKEDATE(2025, 1) + INTERVAL 9 MONTH AS Q4;
Q1Q2Q3Q4
2025-01-012025-04-012025-07-012025-10-01

También puedes usar MAKEDATE como base para cálculos con DATEDIFF, determinando en qué día del año ocurrió cada venta:

SELECT
    fecha,
    total,
    DATEDIFF(fecha, MAKEDATE(YEAR(fecha), 1)) + 1 AS dia_del_anio
FROM pedidos
WHERE YEAR(fecha) = 2025
ORDER BY fecha
LIMIT 5;
fechatotaldia_del_anio
2025-01-03245.503
2025-01-0389.903
2025-01-041350.004
2025-01-05432.755
2025-01-0667.206

En el siguiente artículo veremos MAKETIME para construir un valor de hora.

Escrito por Eduardo Lázaro