Hace algún tiempo me encontre con la necesidad de obtener en una consulta a base de datos el número de días laborables entre dos fechas en una de mis aplicaciones que se alimenta desde una base de datos Oracle. Finalmente lo resolví creando una función que ahora utilizo en muchas otras consultas y, aunque es una tarea bastante sencilla, vamos a ver cómo llevarla a cabo.
¿Por qué una función?
Existen maneras de hacerlo utilizando una consulta, pero después de un buen rato pensando decidí que no tenía sentido perder el tiempo, hacer esto con un procedimiento almacenado (función en este caso) de Oracle es mucho más sencillo y rápido.
Primer paso
El primer objetivo es el de obtener el número de días entre dos fechas dadas sin contar los fines de semana, es decir, quitando los sábados y domingos. Por lo tanto, el procedimiento que vamos a crear recibirá dos parámetros de entrada (fecha de inicio y fecha de fin) y devolverá un valor que será el número de días que buscamos.
Este es el resultado:
1 CREATE OR REPLACE FUNCTION DIAS_LABORABLES 2 (fecha_inicio IN DATE, fecha_fin IN DATE) 3 RETURN NUMBER IS 4 numero_dias NUMBER := 0; 5 fecha_actual DATE; 6 BEGIN 7 IF fecha_fin >= fecha_inicio THEN 8 fecha_actual := fecha_inicio; 9 WHILE fecha_actual <= fecha_fin LOOP 10 IF TO_CHAR(fecha_actual,'DY') NOT IN ('SAT','SUN') THEN 11 numero_dias := numero_dias + 1; 12 END IF; 13 fecha_actual := fecha_actual + 1; 14 END LOOP; 15 RETURN numero_dias; 16 ELSE 17 RETURN 0; 18 END IF; 19 END DIAS_LABORABLES; 20 /
Como véis, es bastante sencillo. En la línea 7 hacemos un sencillo control, para devolver directamente cero si la fecha de fin es menor a la fecha de inicio. En las líneas de la 8 a la 14, vamos recorriendo todos los días entre las dos fechas con un bucle y sumamos un día más a nuestro contador de días cuando el día actual no es ni sábado ni domingo.
Segundo paso
Ahora que ya tenemos una función que nos devuelve el número de días laborables, podemos ir un paso más allá.
En mi caso, como los días festivos varían año tras año, tengo una tabla donde se guardan precisamente los días festivos del año. Por consiguiente, añadiendo unas líneas muy sencillas podemos conseguir que la función nos devuelva el número de días laborables de manera mucho más precisa.
La tabla (FIESTAS_ANO) tendría sencillamente una columna (FECHA) donde se almacena la fecha del día festivo. Sólo habría que recordar que hay que ir completando la tabla cada año.
Pasamos directamente a ver cómo quedaría nuestra función:
1 CREATE OR REPLACE FUNCTION DIAS_LABORABLES 2 (fecha_inicio IN DATE, fecha_fin IN DATE) 3 RETURN NUMBER IS 4 vacaciones NUMBER; 5 numero_dias NUMBER := 0; 6 fecha_actual DATE; 7 BEGIN 8 IF fecha_fin >= fecha_inicio THEN 9 fecha_actual := fecha_inicio; 10 WHILE fecha_actual <= fecha_fin LOOP 11 IF TO_CHAR(fecha_actual,'DY') NOT IN ('SAT','SUN') 12 THEN numero_dias := numero_dias + 1; 13 END IF; 14 fecha_actual := fecha_actual + 1; 15 END LOOP; 16 17 SELECT COUNT (FECHA) 18 INTO vacaciones 19 FROM FIESTAS_ANO 20 WHERE FECHA BETWEEN fecha_inicio AND fecha_fin; 21 22 RETURN numero_dias - vacaciones; 23 ELSE 24 RETURN 0; 25 END IF; 26 END DIAS_LABORABLES; 27 /
Como véis, después de obtener el número de días quitando sábados y domingos, he introducido una sentencia select para contar el número de días de vacaciones entre las dos fechas que indican los parámetros de entrada. Una vez obtenidos los días de vacaciones no hay que olvidarse de devolver la diferencia, y todo listo.