MINUTE
La función MINUTE extrae el componente de minutos de un valor TIME, DATETIME o TIMESTAMP y lo devuelve como un entero entre 0 y 59. Aunque pueda parecer una función de nicho, MINUTE es esencial cuando necesitas analizar datos con granularidad más fina que la hora: intervalos de 15 minutos, bloques de media hora o distribución minuto a minuto de eventos.
En sistemas de alta frecuencia como logs de servidor, transacciones financieras o datos de sensores IoT, agrupar por hora puede ser demasiado grueso. Ahí es donde MINUTE entra en juego, permitiéndote crear ventanas temporales más precisas que revelan patrones invisibles en análisis por hora.
Sintaxis
MINUTE(expresion_tiempo)El argumento puede ser un valor TIME, DATETIME, TIMESTAMP o una cadena con formato de hora válido. Devuelve un entero de 0 a 59 que representa los minutos.
Comportamiento básico
MINUTE devuelve el componente de minutos de cualquier expresión temporal:
SELECT
MINUTE('2025-08-15 14:30:45') AS desde_datetime,
MINUTE('09:45:00') AS desde_time,
MINUTE('2025-08-15 08:05:30') AS cinco_minutos,
MINUTE('2025-08-15 12:00:00') AS cero_minutos;| desde_datetime | desde_time | cinco_minutos | cero_minutos |
|---|---|---|---|
| 30 | 45 | 5 | 0 |
El resultado es siempre un entero sin ceros a la izquierda. Los 5 minutos se devuelven como 5, no como "05". Medianoche en punto devuelve 0 minutos.
MINUTE con TIME extendido
Al igual que HOUR, MINUTE funciona con valores TIME que exceden las 24 horas. El componente de minutos sigue siendo un valor de 0 a 59 independientemente de cuántas horas tenga el valor:
SELECT
MINUTE('100:30:00') AS duracion_larga,
MINUTE('838:59:59') AS maximo_time;| duracion_larga | maximo_time |
|---|---|
| 30 | 59 |
Caso práctico: redondear a intervalos de 15 minutos
Uno de los usos más prácticos de MINUTE es agrupar eventos en intervalos regulares. Para crear bloques de 15 minutos, combinas HOUR y MINUTE con un poco de aritmética:
SELECT
CONCAT(
LPAD(HOUR(fecha_acceso), 2, '0'),
':',
LPAD(FLOOR(MINUTE(fecha_acceso) / 15) * 15, 2, '0')
) AS intervalo,
COUNT(*) AS accesos
FROM log_accesos
WHERE DATE(fecha_acceso) = '2025-01-15'
AND HOUR(fecha_acceso) BETWEEN 9 AND 11
GROUP BY
HOUR(fecha_acceso),
FLOOR(MINUTE(fecha_acceso) / 15)
ORDER BY intervalo;| intervalo | accesos |
|---|---|
| 09:00 | 187 |
| 09:15 | 234 |
| 09:30 | 312 |
| 09:45 | 289 |
| 10:00 | 345 |
| 10:15 | 378 |
| 10:30 | 356 |
| 10:45 | 321 |
| 11:00 | 298 |
| 11:15 | 267 |
| 11:30 | 245 |
| 11:45 | 223 |
La expresión FLOOR(MINUTE(fecha_acceso) / 15) * 15 es la clave: divide los minutos entre 15, redondea hacia abajo con FLOOR y multiplica por 15. Así, los minutos 0-14 se convierten en 0, los minutos 15-29 en 15, los minutos 30-44 en 30 y los minutos 45-59 en 45. Este patrón funciona para cualquier intervalo: cambia el 15 por 5, 10 o 30 según la granularidad que necesites.
Caso práctico: análisis de franjas de media hora
Otro intervalo muy útil es la media hora, especialmente para turnos de atención al cliente o reservas de restaurante:
SELECT
HOUR(hora_reserva) AS hora,
CASE
WHEN MINUTE(hora_reserva) < 30 THEN 'primera media hora'
ELSE 'segunda media hora'
END AS media_hora,
COUNT(*) AS reservas
FROM reservas_restaurante
WHERE fecha_reserva = '2025-01-18'
GROUP BY
HOUR(hora_reserva),
CASE
WHEN MINUTE(hora_reserva) < 30 THEN 'primera media hora'
ELSE 'segunda media hora'
END
ORDER BY hora, media_hora;| hora | media_hora | reservas |
|---|---|---|
| 13 | primera media hora | 12 |
| 13 | segunda media hora | 18 |
| 14 | primera media hora | 22 |
| 14 | segunda media hora | 15 |
| 20 | primera media hora | 8 |
| 20 | segunda media hora | 14 |
| 21 | primera media hora | 25 |
| 21 | segunda media hora | 20 |
Las reservas se concentran en la segunda media hora de las 13h (13:30-13:59), a las 14h en punto (14:00-14:29) y a las 21h en punto (21:00-21:29). Esta distribución tiene sentido: la gente reserva a las 13:30 o a las 14:00, rara vez a las 13:05 o las 13:47.
Caso práctico: identificar picos de carga por minuto
Para sistemas de monitoreo, agrupar por minuto exacto puede revelar picos de carga puntuales que se diluyen en análisis por hora:
SELECT
HOUR(fecha_evento) AS hora,
MINUTE(fecha_evento) AS minuto,
COUNT(*) AS eventos
FROM log_servidor
WHERE DATE(fecha_evento) = '2025-01-15'
AND HOUR(fecha_evento) = 10
GROUP BY
HOUR(fecha_evento),
MINUTE(fecha_evento)
ORDER BY eventos DESC
LIMIT 10;| hora | minuto | eventos |
|---|---|---|
| 10 | 0 | 892 |
| 10 | 30 | 756 |
| 10 | 1 | 534 |
| 10 | 15 | 498 |
| 10 | 31 | 467 |
| 10 | 45 | 445 |
| 10 | 2 | 423 |
| 10 | 29 | 398 |
| 10 | 14 | 387 |
| 10 | 46 | 376 |
El pico masivo en el minuto 0 (10:00 en punto) probablemente corresponde a tareas programadas (cron jobs) que se ejecutan al inicio de la hora. El segundo pico en el minuto 30 confirma esta hipótesis: hay tareas programadas a las horas en punto y a la media hora. Este tipo de descubrimiento es imposible si solo agrupas por hora.
Caso práctico: tiempo de espera en call center
En un call center, MINUTE combinado con HOUR permite analizar el tiempo que los clientes pasan en espera:
SELECT
HOUR(hora_inicio_espera) AS hora,
ROUND(AVG(MINUTE(hora_fin_espera) - MINUTE(hora_inicio_espera)), 1) AS espera_media_min,
MAX(MINUTE(hora_fin_espera) - MINUTE(hora_inicio_espera)) AS espera_maxima_min,
COUNT(*) AS llamadas
FROM llamadas_soporte
WHERE DATE(fecha_llamada) = '2025-01-15'
AND MINUTE(hora_fin_espera) >= MINUTE(hora_inicio_espera)
GROUP BY HOUR(hora_inicio_espera)
HAVING COUNT(*) > 5
ORDER BY hora;| hora | espera_media_min | espera_maxima_min | llamadas |
|---|---|---|---|
| 9 | 3.2 | 12 | 45 |
| 10 | 5.8 | 18 | 67 |
| 11 | 7.1 | 22 | 58 |
| 12 | 4.5 | 15 | 34 |
| 14 | 6.3 | 20 | 62 |
| 15 | 5.1 | 16 | 51 |
| 16 | 3.8 | 11 | 38 |
La hora con mayor espera media es las 11h (7.1 minutos), justo antes del almuerzo cuando el volumen de llamadas sigue alto pero parte del equipo ya está en pausa. Para análisis de duraciones más largos que puedan cruzar la frontera de la hora, es mejor usar TIMESTAMPDIFF(MINUTE, inicio, fin) en lugar de restar minutos directamente.
MINUTE con NULL
MINUTE devuelve NULL cuando la entrada es NULL:
SELECT
MINUTE(NULL) AS resultado;| resultado |
|---|
| NULL |
Como con todas las funciones de fecha, el NULL se propaga sin errores.
Combinación con otras funciones
MINUTE se combina naturalmente con HOUR para crear timestamps parciales, y con SEC_TO_TIME para reconstruir valores de tiempo:
SELECT
fecha_venta,
CONCAT(
LPAD(HOUR(fecha_venta), 2, '0'), ':',
LPAD(MINUTE(fecha_venta), 2, '0')
) AS hora_minuto,
HOUR(fecha_venta) * 60 + MINUTE(fecha_venta) AS minutos_desde_medianoche
FROM ventas
WHERE DATE(fecha_venta) = '2024-12-24'
ORDER BY fecha_venta
LIMIT 5;| fecha_venta | hora_minuto | minutos_desde_medianoche |
|---|---|---|
| 2024-12-24 08:15:33 | 08:15 | 495 |
| 2024-12-24 08:22:10 | 08:22 | 502 |
| 2024-12-24 09:01:45 | 09:01 | 541 |
| 2024-12-24 09:05:22 | 09:05 | 545 |
| 2024-12-24 09:18:07 | 09:18 | 558 |
El cálculo HOUR * 60 + MINUTE convierte la hora y minutos a un único número (minutos desde medianoche), lo cual es muy útil para comparaciones y cálculos numéricos. Las 08:15 son 495 minutos desde medianoche (8 * 60 + 15 = 495). Esta técnica simplifica las comparaciones de rangos horarios en cláusulas WHERE.
En el siguiente artículo veremos SECOND para extraer los segundos.
Escrito por Eduardo Lázaro
