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_dia | fin_enero | inicio_febrero | fin_anio |
|---|---|---|---|
| 2025-01-01 | 2025-01-31 | 2025-02-01 | 2025-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_bisiesto | dia60_normal | ultimo_bisiesto |
|---|---|---|
| 2024-02-29 | 2025-03-01 | 2024-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_366 | dia_400 |
|---|---|
| 2026-01-01 | 2026-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_original | dia_del_anio | reconstruida |
|---|---|---|
| 2025-03-15 | 74 | 2025-03-15 |
| 2025-07-04 | 185 | 2025-07-04 |
| 2025-12-25 | 359 | 2025-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;| fecha | pedidos |
|---|---|
| 2025-01-01 | 0 |
| 2025-01-06 | 0 |
| 2025-02-14 | 0 |
| 2025-03-09 | 0 |
| 2025-03-23 | 0 |
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_lote | anio | dia_juliano | fecha_produccion |
|---|---|---|---|
| LOT-2025-074 | 2025 | 74 | 2025-03-15 |
| LOT-2025-185 | 2025 | 185 | 2025-07-04 |
| LOT-2024-366 | 2024 | 366 | 2024-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_nulo | dia_nulo | dia_cero | dia_negativo |
|---|---|---|---|
| NULL | NULL | NULL | NULL |
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;| Q1 | Q2 | Q3 | Q4 |
|---|---|---|---|
| 2025-01-01 | 2025-04-01 | 2025-07-01 | 2025-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;| fecha | total | dia_del_anio |
|---|---|---|
| 2025-01-03 | 245.50 | 3 |
| 2025-01-03 | 89.90 | 3 |
| 2025-01-04 | 1350.00 | 4 |
| 2025-01-05 | 432.75 | 5 |
| 2025-01-06 | 67.20 | 6 |
En el siguiente artículo veremos MAKETIME para construir un valor de hora.
Escrito por Eduardo Lázaro
