Hace unos días, en una formación, una alumna me preguntaba por la existencia de alguna función que calculara los días laborables transcurridos entre dos fechas, pero contando solo los días de la semana que ella indicara de manera personalizada.
Ella necesitaba personalizar los días laborables en cada caso (solo Lunes y Jueves, o solo Lunes, Martes y Viernes, etc). Le desarrollé de manera improvisada una fórmula para salir del paso; pero tras acabar la formación, pensé en hacer esa fórmula más general y extensiva para cualquier caso.
Y ese es el tema de hoy.
Dada una fecha inicial (celda B2) y otra final (celda C2), queremos conocer cuántos días de los elegidos en la celda D2, abreviados con una letra (L,M,X,J,V,S,D) y separados por la barra vertical, indiquemos (ejemplo: L|J, o L|X|S|D, etc).
Emplearé la función LET (a la espera la función LAMDA sea de uso general).
Así mismo emplearé en el desarrollo dos cálculos ya vistos en el blog:
- Separar caracteres (ver aquí)
- Producto de condiciones con criterio lógico O (ver aquí)
Con los antecedentes expuesto, veammos la fórmula buscada en E2:
=LET(FechaInicial;B2;
FechaFinal;C2;
DiasLab;TRANSPONER(XMLFILTRO("<i><f><d>"&SUSTITUIR(D2;"|";"</d><d>")&"</d></f></i>";"//f/d"));
SerieEntreFechas;SECUENCIA(FechaFinal-FechaInicial+1;1;FechaInicial);
DiasSemana;DIASEM(SerieEntreFechas;2);
PosDiasLab;COINCIDIR(DiasLab;{"L"\"M"\"X"\"J"\"V"\"S"\"D"};0);
Coincidencias;DiasSemana=PosDiasLab;
SUMAPRODUCTO(MMULT(--Coincidencias;SECUENCIA(COLUMNAS(Coincidencias);1;1;0)))
)
Podemos ver el paso a paso que realiza la fórmula descomponiendo cada línea...
El primer paso es simple y ya visto:
DiasLab;TRANSPONER(XMLFILTRO("<i><f><d>"&SUSTITUIR(D2;"|";"</d><d>")&"</d></f></i>";"//f/d"));
con esta función dividimos un cadena de texto, como la del ejemplo: L|V, en un vector de n columnas {L\V}.
En el siguiente paso generamos la serie de todas las fechas posibles entre las dos dadas con la función SECUENCIA:
SerieEntreFechas;SECUENCIA(FechaFinal-FechaInicial+1;1;FechaInicial)
obteniendo un vector de dichas fechas...
A continuación calculamos para cada fecha de nuestra serie aplicándole la función DIASEM:
DiasSemana;DIASEM(SerieEntreFechas;2)
esto nos convierte la serie de fechas en un nuevo vector de números del 1 al 7 (con una equivalencia: lunes=1, martes=2,..., domingo=7).
Un paso importante es el siguiente. Aquí obtenemos y transformamos el texto de días buscados en números del 1 al 7. Esto es, si busco L|V, necesito un 1 y un 5.
Esto lo conseguimos con la función COINCIDIR: PosDiasLab;COINCIDIR(DiasLab;{"L"\"M"\"X"\"J"\"V"\"S"\"D"};0)
Ya casi estamos...
Si cruzamos ambos vectores: días buscados con días listados:
Coincidencias;DiasSemana=PosDiasLab
obtendremos una matriz de FALSOS y VERDADEROS de acuerdo a dichas coincidencias...
Solo nos queda sumar y acumular coincidencias. Último paso:
SUMAPRODUCTO(MMULT(--Coincidencias;SECUENCIA(COLUMNAS(Coincidencias);1;1;0)))
Con la técnica descrita aquí, tendremos nuestro resultado final...
Listo. Tenemos una fórmula personalizada para obtener el número de días laborables, personalizados por nosotros, entre dos fechas dadas.
Finalmente, podríamos incorporar el concepto de festivos:
En la celda E3 y teniendo el cuenta el rango de festivos dado en B7:B9.
=LET(FechaInicial;B2;
FechaFinal;C2;
rangoFestivos;B7:B9;
DiasLab;TRANSPONER(XMLFILTRO("<i><f><d>"&SUSTITUIR(D2;"|";"</d><d>")&"</d></f></i>";"//f/d"));
SerieEntreFechas;SECUENCIA(FechaFinal-FechaInicial+1;1;FechaInicial);
DiasSemana;DIASEM(SerieEntreFechas;2);
PosDiasLab;COINCIDIR(DiasLab;{"L"\"M"\"X"\"J"\"V"\"S"\"D"};0);
Coincidencias;DiasSemana=PosDiasLab;
CruceFestivos;-MMULT(SI(SerieEntreFechas=TRANSPONER(rangoFestivos);1;0);SECUENCIA(FILAS(rangoFestivos);1;1;0));
SUMA(--((MMULT(--Coincidencias;SECUENCIA(COLUMNAS(Coincidencias);1;1;0))+CruceFestivos)>0)))
¡¡Anticipo!!. En dos días publicaré una solución estándar de Excel.
Ella necesitaba personalizar los días laborables en cada caso (solo Lunes y Jueves, o solo Lunes, Martes y Viernes, etc). Le desarrollé de manera improvisada una fórmula para salir del paso; pero tras acabar la formación, pensé en hacer esa fórmula más general y extensiva para cualquier caso.
Y ese es el tema de hoy.
Dada una fecha inicial (celda B2) y otra final (celda C2), queremos conocer cuántos días de los elegidos en la celda D2, abreviados con una letra (L,M,X,J,V,S,D) y separados por la barra vertical, indiquemos (ejemplo: L|J, o L|X|S|D, etc).
Emplearé la función LET (a la espera la función LAMDA sea de uso general).
Así mismo emplearé en el desarrollo dos cálculos ya vistos en el blog:
- Separar caracteres (ver aquí)
- Producto de condiciones con criterio lógico O (ver aquí)
Con los antecedentes expuesto, veammos la fórmula buscada en E2:
=LET(FechaInicial;B2;
FechaFinal;C2;
DiasLab;TRANSPONER(XMLFILTRO("<i><f><d>"&SUSTITUIR(D2;"|";"</d><d>")&"</d></f></i>";"//f/d"));
SerieEntreFechas;SECUENCIA(FechaFinal-FechaInicial+1;1;FechaInicial);
DiasSemana;DIASEM(SerieEntreFechas;2);
PosDiasLab;COINCIDIR(DiasLab;{"L"\"M"\"X"\"J"\"V"\"S"\"D"};0);
Coincidencias;DiasSemana=PosDiasLab;
SUMAPRODUCTO(MMULT(--Coincidencias;SECUENCIA(COLUMNAS(Coincidencias);1;1;0)))
)
Podemos ver el paso a paso que realiza la fórmula descomponiendo cada línea...
El primer paso es simple y ya visto:
DiasLab;TRANSPONER(XMLFILTRO("<i><f><d>"&SUSTITUIR(D2;"|";"</d><d>")&"</d></f></i>";"//f/d"));
con esta función dividimos un cadena de texto, como la del ejemplo: L|V, en un vector de n columnas {L\V}.
En el siguiente paso generamos la serie de todas las fechas posibles entre las dos dadas con la función SECUENCIA:
SerieEntreFechas;SECUENCIA(FechaFinal-FechaInicial+1;1;FechaInicial)
obteniendo un vector de dichas fechas...
A continuación calculamos para cada fecha de nuestra serie aplicándole la función DIASEM:
DiasSemana;DIASEM(SerieEntreFechas;2)
esto nos convierte la serie de fechas en un nuevo vector de números del 1 al 7 (con una equivalencia: lunes=1, martes=2,..., domingo=7).
Un paso importante es el siguiente. Aquí obtenemos y transformamos el texto de días buscados en números del 1 al 7. Esto es, si busco L|V, necesito un 1 y un 5.
Esto lo conseguimos con la función COINCIDIR: PosDiasLab;COINCIDIR(DiasLab;{"L"\"M"\"X"\"J"\"V"\"S"\"D"};0)
Ya casi estamos...
Si cruzamos ambos vectores: días buscados con días listados:
Coincidencias;DiasSemana=PosDiasLab
obtendremos una matriz de FALSOS y VERDADEROS de acuerdo a dichas coincidencias...
Solo nos queda sumar y acumular coincidencias. Último paso:
SUMAPRODUCTO(MMULT(--Coincidencias;SECUENCIA(COLUMNAS(Coincidencias);1;1;0)))
Con la técnica descrita aquí, tendremos nuestro resultado final...
Listo. Tenemos una fórmula personalizada para obtener el número de días laborables, personalizados por nosotros, entre dos fechas dadas.
Finalmente, podríamos incorporar el concepto de festivos:
En la celda E3 y teniendo el cuenta el rango de festivos dado en B7:B9.
=LET(FechaInicial;B2;
FechaFinal;C2;
rangoFestivos;B7:B9;
DiasLab;TRANSPONER(XMLFILTRO("<i><f><d>"&SUSTITUIR(D2;"|";"</d><d>")&"</d></f></i>";"//f/d"));
SerieEntreFechas;SECUENCIA(FechaFinal-FechaInicial+1;1;FechaInicial);
DiasSemana;DIASEM(SerieEntreFechas;2);
PosDiasLab;COINCIDIR(DiasLab;{"L"\"M"\"X"\"J"\"V"\"S"\"D"};0);
Coincidencias;DiasSemana=PosDiasLab;
CruceFestivos;-MMULT(SI(SerieEntreFechas=TRANSPONER(rangoFestivos);1;0);SECUENCIA(FILAS(rangoFestivos);1;1;0));
SUMA(--((MMULT(--Coincidencias;SECUENCIA(COLUMNAS(Coincidencias);1;1;0))+CruceFestivos)>0)))
¡¡Anticipo!!. En dos días publicaré una solución estándar de Excel.
No hay comentarios:
Publicar un comentario
Nota: solo los miembros de este blog pueden publicar comentarios.