WEEKDAY
La funcion WEEKDAY() devuelve un indice numerico que representa el dia de la semana de una fecha, usando una escala donde 0 es lunes y 6 es domingo. Esta convencion se alinea con el estandar ISO y con la forma en que la mayoria de paises europeos y latinoamericanos organizan la semana, lo que la hace particularmente practica cuando trabajas en entornos donde el lunes es el primer dia laborable.
Sintaxis
WEEKDAY(fecha)El parametro fecha acepta valores de tipo DATE o DATETIME. La funcion devuelve un entero entre 0 y 6 segun esta correspondencia:
| Valor | Dia |
|---|---|
| 0 | Lunes |
| 1 | Martes |
| 2 | Miercoles |
| 3 | Jueves |
| 4 | Viernes |
| 5 | Sabado |
| 6 | Domingo |
La principal diferencia con DAYOFWEEK() es la escala. DAYOFWEEK() sigue el estandar ODBC (1 = domingo, 7 = sabado), mientras que WEEKDAY() sigue la convencion ISO (0 = lunes, 6 = domingo). Es una distincion sutil pero critica que puede producir errores dificiles de detectar si confundes ambas funciones.
Comportamiento basico
Para obtener el indice del dia de la semana:
SELECT WEEKDAY('2026-02-14') AS dia_indice;| dia_indice |
|---|
| 5 |
El 14 de febrero de 2026 es sabado, que corresponde al indice 5. Puedes verificar toda una semana para entender la correspondencia:
SELECT
fecha,
WEEKDAY(fecha) AS weekday_idx,
DAYNAME(fecha) AS nombre_dia
FROM (
SELECT '2026-02-09' AS fecha
UNION SELECT '2026-02-10'
UNION SELECT '2026-02-11'
UNION SELECT '2026-02-12'
UNION SELECT '2026-02-13'
UNION SELECT '2026-02-14'
UNION SELECT '2026-02-15'
) dias
ORDER BY fecha;| fecha | weekday_idx | nombre_dia |
|---|---|---|
| 2026-02-09 | 0 | Monday |
| 2026-02-10 | 1 | Tuesday |
| 2026-02-11 | 2 | Wednesday |
| 2026-02-12 | 3 | Thursday |
| 2026-02-13 | 4 | Friday |
| 2026-02-14 | 5 | Saturday |
| 2026-02-15 | 6 | Sunday |
La secuencia va de 0 (lunes) a 6 (domingo), lo que resulta natural para contextos laborales donde la semana empieza el lunes.
Caso practico: filtrar dias laborables
WEEKDAY() facilita el filtrado de dias laborables porque los valores del 0 al 4 corresponden exactamente a lunes-viernes:
SELECT
fecha_pedido,
total,
WEEKDAY(fecha_pedido) AS dia_idx
FROM pedidos
WHERE WEEKDAY(fecha_pedido) <= 4
AND fecha_pedido BETWEEN '2026-02-09' AND '2026-02-15'
ORDER BY fecha_pedido;| fecha_pedido | total | dia_idx |
|---|---|---|
| 2026-02-09 | 445.00 | 0 |
| 2026-02-10 | 156.40 | 1 |
| 2026-02-11 | 278.30 | 2 |
| 2026-02-12 | 95.80 | 3 |
| 2026-02-13 | 342.00 | 4 |
La condicion WEEKDAY(fecha_pedido) <= 4 es mas limpia y legible que el equivalente con DAYOFWEEK(), que requeriria DAYOFWEEK(fecha_pedido) BETWEEN 2 AND 6. Del mismo modo, para seleccionar solo fines de semana basta con WEEKDAY(fecha_pedido) >= 5.
Puedes calcular cuantos dias laborables hay en un periodo:
SELECT
COUNT(DISTINCT DATE(fecha_pedido)) AS dias_con_ventas,
SUM(CASE WHEN WEEKDAY(fecha_pedido) <= 4 THEN 1 ELSE 0 END) AS pedidos_laborables,
SUM(CASE WHEN WEEKDAY(fecha_pedido) >= 5 THEN 1 ELSE 0 END) AS pedidos_fin_semana
FROM pedidos
WHERE fecha_pedido BETWEEN '2026-01-01' AND '2026-01-31';| dias_con_ventas | pedidos_laborables | pedidos_fin_semana |
|---|---|---|
| 30 | 145 | 38 |
Caso practico: rendimiento por dia de la semana en orden natural
Cuando generas un reporte de ventas agrupado por dia, WEEKDAY() te permite ordenar de lunes a domingo de forma directa:
SET lc_time_names = 'es_ES';
SELECT
WEEKDAY(fecha_pedido) AS idx,
DAYNAME(fecha_pedido) AS dia,
COUNT(*) AS pedidos,
ROUND(SUM(total), 2) AS ingresos,
ROUND(AVG(total), 2) AS ticket_medio
FROM pedidos
WHERE YEAR(fecha_pedido) = 2025
GROUP BY WEEKDAY(fecha_pedido), DAYNAME(fecha_pedido)
ORDER BY WEEKDAY(fecha_pedido);| idx | dia | pedidos | ingresos | ticket_medio |
|---|---|---|---|---|
| 0 | lunes | 187 | 45320.50 | 242.36 |
| 1 | martes | 162 | 38750.80 | 239.20 |
| 2 | miercoles | 174 | 41200.30 | 236.78 |
| 3 | jueves | 195 | 48900.00 | 250.77 |
| 4 | viernes | 231 | 62450.75 | 270.35 |
| 5 | sabado | 145 | 35100.20 | 242.07 |
| 6 | domingo | 98 | 22800.40 | 232.66 |
Con ORDER BY WEEKDAY(fecha_pedido), los resultados aparecen en el orden natural de lunes a domingo sin necesidad de trucos adicionales. Esto es mas limpio que usar DAYOFWEEK() donde tendrias que ajustar el orden con una expresion aritmetica para que lunes aparezca primero.
Caso practico: calcular el lunes de la semana actual
Un patron comun es encontrar el primer dia (lunes) de la semana de una fecha dada. Con WEEKDAY() esto es directo:
SELECT
CURDATE() AS hoy,
WEEKDAY(CURDATE()) AS dia_idx,
DATE_SUB(CURDATE(), INTERVAL WEEKDAY(CURDATE()) DAY) AS lunes_de_esta_semana;| hoy | dia_idx | lunes_de_esta_semana |
|---|---|---|
| 2026-02-14 | 5 | 2026-02-09 |
La formula DATE_SUB(fecha, INTERVAL WEEKDAY(fecha) DAY) resta tantos dias como indica el indice de WEEKDAY(), lo que siempre te lleva al lunes de esa semana. Puedes aplicar esto para agrupar ventas por semana empezando en lunes:
SELECT
DATE_SUB(fecha_pedido, INTERVAL WEEKDAY(fecha_pedido) DAY) AS semana_inicio,
COUNT(*) AS pedidos,
ROUND(SUM(total), 2) AS ingresos
FROM pedidos
WHERE fecha_pedido BETWEEN '2026-01-01' AND '2026-01-31'
GROUP BY DATE_SUB(fecha_pedido, INTERVAL WEEKDAY(fecha_pedido) DAY)
ORDER BY semana_inicio;| semana_inicio | pedidos | ingresos |
|---|---|---|
| 2025-12-29 | 12 | 2950.30 |
| 2026-01-05 | 52 | 13200.50 |
| 2026-01-12 | 48 | 12100.80 |
| 2026-01-19 | 55 | 14350.20 |
| 2026-01-26 | 44 | 10800.40 |
Manejo de NULL
WEEKDAY() devuelve NULL si la fecha es nula o invalida:
SELECT
WEEKDAY(NULL) AS resultado_null,
WEEKDAY('2025-04-31') AS abril_invalido;| resultado_null | abril_invalido |
|---|---|
| NULL | NULL |
El 31 de abril no existe (abril tiene 30 dias), asi que MySQL no puede determinar el dia de la semana y devuelve NULL. En consultas sobre tablas con fechas opcionales, puedes protegerte con COALESCE:
SELECT
nombre,
COALESCE(WEEKDAY(fecha_baja), -1) AS dia_baja
FROM empleados;Combinacion con otras funciones
La relacion entre WEEKDAY() y DAYOFWEEK() se puede expresar con una formula. Ambas devuelven el dia de la semana pero con escalas diferentes:
SELECT
CURDATE() AS fecha,
WEEKDAY(CURDATE()) AS weekday_val,
DAYOFWEEK(CURDATE()) AS dayofweek_val,
MOD(WEEKDAY(CURDATE()) + 1, 7) + 1 AS weekday_to_dayofweek;| fecha | weekday_val | dayofweek_val | weekday_to_dayofweek |
|---|---|---|---|
| 2026-02-14 | 5 | 7 | 7 |
Puedes combinar WEEKDAY() con ELT() para crear tu propia version localizada de nombres de dias sin depender de lc_time_names:
SELECT
fecha_pedido,
ELT(WEEKDAY(fecha_pedido) + 1,
'Lunes', 'Martes', 'Miércoles', 'Jueves',
'Viernes', 'Sábado', 'Domingo') AS dia_espanol,
total
FROM pedidos
ORDER BY fecha_pedido DESC
LIMIT 5;| fecha_pedido | dia_espanol | total |
|---|---|---|
| 2026-02-14 | Sabado | 189.50 |
| 2026-02-13 | Viernes | 342.00 |
| 2026-02-12 | Jueves | 95.80 |
| 2026-02-11 | Miercoles | 278.30 |
| 2026-02-10 | Martes | 156.40 |
La funcion ELT() devuelve el elemento en la posicion indicada por el primer argumento. Como WEEKDAY() devuelve 0 para lunes, sumamos 1 para que coincida con la posicion en ELT() (que empieza en 1). Esta tecnica te da control total sobre los nombres sin depender de la configuracion del locale del servidor.
En el siguiente articulo veremos YEARWEEK para obtener ano y semana combinados.
Escrito por Eduardo Lázaro
