La función TIME_FORMAT() convierte un valor de tipo TIME en una cadena de texto con el formato que especifiques. Funciona de manera similar a DATE_FORMAT(), pero está diseñada exclusivamente para valores temporales y solo acepta los especificadores relacionados con horas, minutos y segundos. Los especificadores de fecha como %Y, %m o %d producen NULL o valores vacíos cuando se usan con TIME_FORMAT().
Esta función es la herramienta adecuada cuando necesitas presentar horas en formatos legibles, como convertir 14:32:08 a 2:32 PM, mostrar duraciones en un formato amigable o adaptar la representación horaria a las convenciones locales de presentación.
Sintaxis
TIME_FORMAT(hora, formato)El primer argumento es un valor de tipo TIME, un DATETIME (del cual se usará solo la parte horaria) o una cadena que MySQL pueda interpretar como hora. El segundo argumento es la cadena de formato con especificadores precedidos por %.
Los especificadores válidos para TIME_FORMAT() son los mismos que los especificadores de hora de DATE_FORMAT():
| Especificador | Descripción | Ejemplo |
|---|---|---|
%H | Hora 24h con cero inicial (00-23) | 14 |
%k | Hora 24h sin cero inicial (0-23) | 14 |
%h o %I | Hora 12h con cero inicial (01-12) | 02 |
%l | Hora 12h sin cero inicial (1-12) | 2 |
%i | Minutos con cero inicial (00-59) | 32 |
%s o %S | Segundos con cero inicial (00-59) | 08 |
%f | Microsegundos (000000-999999) | 451293 |
%p | Indicador AM/PM | PM |
%r | Hora completa en formato 12h | 02:32:08 PM |
%T | Hora completa en formato 24h | 14:32:08 |
Comportamiento básico
La operación más común de TIME_FORMAT() es convertir entre formato de 24 horas y formato de 12 horas con indicador AM/PM.
SELECT TIME_FORMAT('14:32:08', '%h:%i:%s %p') AS formato_12h;| formato_12h |
|---|
| 02:32:08 PM |
El proceso inverso, mostrar una hora en formato de 24 horas con el formato compuesto %T, es igualmente directo.
SELECT TIME_FORMAT('02:32:08', '%T') AS formato_24h;| formato_24h |
|---|
| 02:32:08 |
Puedes simplificar la salida omitiendo los segundos cuando no son relevantes.
SELECT TIME_FORMAT('14:32:08', '%H:%i') AS sin_segundos_24h,
TIME_FORMAT('14:32:08', '%h:%i %p') AS sin_segundos_12h;| sin_segundos_24h | sin_segundos_12h |
|---|---|
| 14:32 | 02:32 PM |
La opción %l muestra la hora en formato de 12 horas sin el cero inicial, lo que resulta más natural para lectura humana.
SELECT TIME_FORMAT('09:05:00', '%h:%i %p') AS con_cero,
TIME_FORMAT('09:05:00', '%l:%i %p') AS sin_cero;| con_cero | sin_cero |
|---|---|
| 09:05 AM | 9:05 AM |
También puedes incluir texto literal en la cadena de formato.
SELECT TIME_FORMAT('14:32:08', '%H horas, %i minutos y %s segundos') AS descriptivo;| descriptivo |
|---|
| 14 horas, 32 minutos y 08 segundos |
Caso práctico: presentar horarios de atención
Imagina que tienes una tabla con los horarios de atención de las sucursales de un negocio y necesitas mostrarlos en un formato amigable para los clientes.
CREATE TABLE sucursales (
id INT AUTO_INCREMENT PRIMARY KEY,
nombre VARCHAR(100) NOT NULL,
hora_apertura TIME NOT NULL,
hora_cierre TIME NOT NULL,
ciudad VARCHAR(50) NOT NULL
);
SELECT nombre, ciudad,
CONCAT(
TIME_FORMAT(hora_apertura, '%l:%i %p'),
' - ',
TIME_FORMAT(hora_cierre, '%l:%i %p')
) AS horario
FROM sucursales
ORDER BY ciudad, nombre;| nombre | ciudad | horario |
|---|---|---|
| Centro Comercial | Guadalajara | 10:00 AM - 9:00 PM |
| Plaza Universidad | Guadalajara | 9:00 AM - 8:00 PM |
| Sucursal Centro | México DF | 8:30 AM - 6:30 PM |
| Sucursal Polanco | México DF | 9:00 AM - 8:00 PM |
| Sucursal Valle | Monterrey | 8:00 AM - 7:00 PM |
Este formato es mucho más legible para los clientes que mostrar 08:30:00 - 18:30:00.
Para calcular y mostrar la duración del horario de atención en formato legible, combina TIMEDIFF con TIME_FORMAT().
SELECT nombre,
TIME_FORMAT(hora_apertura, '%l:%i %p') AS abre,
TIME_FORMAT(hora_cierre, '%l:%i %p') AS cierra,
TIME_FORMAT(TIMEDIFF(hora_cierre, hora_apertura), '%H:%i') AS horas_servicio
FROM sucursales;| nombre | abre | cierra | horas_servicio |
|---|---|---|---|
| Sucursal Centro | 8:30 AM | 6:30 PM | 10:00 |
| Sucursal Polanco | 9:00 AM | 8:00 PM | 11:00 |
| Centro Comercial | 10:00 AM | 9:00 PM | 11:00 |
| Plaza Universidad | 9:00 AM | 8:00 PM | 11:00 |
| Sucursal Valle | 8:00 AM | 7:00 PM | 11:00 |
Caso práctico: formatear registros de asistencia
En un sistema de control de asistencia, los empleados ven sus horas de entrada y salida. Presentar estas horas en formato de 12 horas con AM/PM es más intuitivo que el formato militar de 24 horas.
SELECT e.nombre,
TIME_FORMAT(ra.hora_entrada, '%h:%i %p') AS entrada,
TIME_FORMAT(ra.hora_salida, '%h:%i %p') AS salida,
TIME_FORMAT(
TIMEDIFF(ra.hora_salida, ra.hora_entrada),
'%H h %i min'
) AS trabajado
FROM registros_asistencia ra
JOIN empleados e ON e.id = ra.empleado_id
WHERE ra.fecha = '2025-07-15'
AND ra.hora_salida IS NOT NULL;| nombre | entrada | salida | trabajado |
|---|---|---|---|
| Carlos Ruiz | 08:47 AM | 05:30 PM | 08 h 42 min |
| Ana Martínez | 09:03 AM | 05:15 PM | 08 h 12 min |
| Pedro Sánchez | 09:22 AM | 06:00 PM | 08 h 37 min |
El formato '%H h %i min' produce una representación de duración clara y legible. Ten en cuenta que %H en este contexto muestra las horas totales de la diferencia, no una hora del reloj, ya que el valor proviene de TIMEDIFF.
Caso práctico: comparar formato 12h y 24h en reportes
A veces necesitas mostrar ambos formatos lado a lado, por ejemplo, en un sistema que atiende regiones con diferentes convenciones horarias.
SELECT p.id,
TIME_FORMAT(TIME(p.fecha_pedido), '%T') AS hora_24h,
TIME_FORMAT(TIME(p.fecha_pedido), '%r') AS hora_12h,
TIME_FORMAT(TIME(p.fecha_pedido), '%h:%i %p') AS hora_corta
FROM pedidos p
WHERE p.fecha_pedido >= '2025-07-14'
ORDER BY p.fecha_pedido;| id | hora_24h | hora_12h | hora_corta |
|---|---|---|---|
| 85 | 09:15:22 | 09:15:22 AM | 09:15 AM |
| 86 | 14:32:08 | 02:32:08 PM | 02:32 PM |
| 87 | 14:32:08 | 02:32:08 PM | 02:32 PM |
El especificador %r es un atajo para %h:%i:%s %p, mientras que %T equivale a %H:%i:%s. Ambos ahorran la escritura de los especificadores individuales cuando necesitas la hora completa.
Las horas de medianoche y mediodía merecen atención especial en formato de 12 horas.
SELECT TIME_FORMAT('00:00:00', '%h:%i %p') AS medianoche,
TIME_FORMAT('12:00:00', '%h:%i %p') AS mediodia,
TIME_FORMAT('00:30:00', '%h:%i %p') AS madrugada;| medianoche | mediodia | madrugada |
|---|---|---|
| 12:00 AM | 12:00 PM | 12:30 AM |
Medianoche se representa como 12:00 AM y mediodía como 12:00 PM, siguiendo la convención estándar del formato de 12 horas.
Manejo de NULL
Si cualquiera de los dos argumentos es NULL, TIME_FORMAT() devuelve NULL.
SELECT TIME_FORMAT(NULL, '%H:%i') AS hora_nula,
TIME_FORMAT('14:32:08', NULL) AS formato_nulo;| hora_nula | formato_nulo |
|---|---|
| NULL | NULL |
Al trabajar con columnas que pueden contener valores nulos, proporciona un texto alternativo con COALESCE.
SELECT e.nombre,
TIME_FORMAT(ra.hora_entrada, '%h:%i %p') AS entrada,
COALESCE(
TIME_FORMAT(ra.hora_salida, '%h:%i %p'),
'En oficina'
) AS salida
FROM registros_asistencia ra
JOIN empleados e ON e.id = ra.empleado_id
WHERE ra.fecha = CURDATE();| nombre | entrada | salida |
|---|---|---|
| Carlos Ruiz | 08:47 AM | 05:30 PM |
| Ana Martínez | 09:03 AM | En oficina |
Combinación con otras funciones
TIME_FORMAT() se integra naturalmente con las funciones de extracción y cálculo temporal.
SELECT TIME_FORMAT(CURTIME(), '%h:%i %p') AS hora_actual,
TIME_FORMAT(ADDTIME(CURTIME(), '02:00:00'), '%h:%i %p') AS en_dos_horas,
TIME_FORMAT(SUBTIME(CURTIME(), '03:30:00'), '%h:%i %p') AS hace_tres_y_media,
TIME_FORMAT(SEC_TO_TIME(3661), '%H h %i min %s seg') AS desde_segundos;| hora_actual | en_dos_horas | hace_tres_y_media | desde_segundos |
|---|---|---|---|
| 02:32 PM | 04:32 PM | 11:02 AM | 01 h 01 min 01 seg |
La función SEC_TO_TIME convierte un número de segundos en un valor TIME, que luego TIME_FORMAT() puede presentar en cualquier formato deseado. Esta combinación es útil para mostrar duraciones calculadas a partir de segundos totales.
Para extraer la hora de un DATETIME y formatearla directamente, puedes pasar el DATETIME completo a TIME_FORMAT(), que ignorará la parte de fecha automáticamente.
SELECT fecha_pedido,
TIME_FORMAT(fecha_pedido, '%h:%i %p') AS hora_formateada
FROM pedidos
WHERE id = 86;| fecha_pedido | hora_formateada |
|---|---|
| 2025-07-15 14:32:08 | 02:32 PM |
Aunque TIME_FORMAT() acepta un DATETIME como entrada, conceptualmente es más claro usar DATE_FORMAT() cuando trabajas con valores DATETIME, reservando TIME_FORMAT() para columnas que almacenan exclusivamente horas o para resultados de funciones que devuelven TIME, como TIMEDIFF() o SEC_TO_TIME().
En el siguiente artículo veremos DATE_ADD para sumar intervalos a una fecha.
Escrito por Eduardo Lázaro
