[pyar] Contar dias habiles

Germán L. Osella Massa gosella en gmail.com
Jue Mar 1 19:49:33 -03 2018


Hola Luciano,

Efectivamente numpy.busday_count() excluye en el cómputo a las fechas dadas
en enddates, siguiendo la costumbre de como se suelen definir los
intervalos en Python (pensá en los índices de una lista o un range()).

Para cambiar eso, lo más fácil sería incrementar la fecha final en un día
haciendo, por ejemplo, datetime.date.today() + datetime,timedelta(days=1) (y
que funciona incluso si enddates es un array conteniendo más de una fecha).

Eso arrojaría el resultado que buscás (ya que contempla también al día
final del rango).

Ahora, si no querés/necesitás tener a Numpy como dependencia, podés
calcularlo fácilmente (y sin necesidad de contar uno por uno todos los
domingos, que la electricidad está cada vez más cara ;-):

Si inicio y fin contienen los dos extremos del rango de fechas que querés
procesar (begindates y enddates en busday_count()), se puede calcular la
cantidad total de días entre esas dos fechas haciendo:

dias = (fin - inicio).days

Podemos ver cuantas semanas completas hay en esa cantidad de días
dividiéndolos por 7, lo que puede arrojar además un resto ya que no
necesariamente habrán semanas completas:

semanas, resto = divmod(dias, 7)

Sabemos que por cada semana completa tenemos un domingo.

Ahora, puede suceder que los días que nos sobran estuvieran todos antes de
la primer semana completa, todos después de la última semana completa o,
más probablemente, repartidos entre ambos casos.
Si tuviéramos al menos a uno de esos días antes de la primer semana
completa, tendríamos que incluir un domingo extra en la cuenta.

Sabiendo el día de la semana de la fecha de inicio (inicio.weekday()), si
es un lunes (inicio.weekday() == 0), es una semana completa y ya está
contemplada en la cuenta anterior.
Si, en cambio, es un martes (inicio.weekday() == 1), tenemos 6 días antes
de la primer semana completa.
Si fuera un miércoles (inicio.weekday() == 2), tenemos 5 días.
Si fuera un jueves (inicio.weekday() == 3), tenemos 4 días.
Si fuera un viernes (inicio.weekday() == 4), tenemos 3 días.
Si fuera un sábado (inicio.weekday() == 5), tenemos 2 días.
Y si fuera un domingo (inicio.weekday() == 6), tenemos sólo 1 día.

Así, si los días que nos sobran son igual o más que los que necesitamos
para llenar la primera semana incompleta, agregamos un domingo más a la
cantidad calculada.

if resto >= 7 - inicio.weekday():
    semanas += 1

Finalmente, calculamos la cantidad de días hábiles como la cantidad de días
entre esas fechas menos la cantidad de domingos (o semanas) que hubo:

dias_hábiles = dias - semanas

En resumen:

def dias_hábiles(inicio, fin):
    dias = (fin - inicio).days
    semanas, resto = divmod(dias, 7)
    if resto >= 7 - inicio.weekday():
        semanas += 1
    return dias - semanas

Así,

>>> dias_hábiles(datetime.date(2018, 2, 1), datetime.date(2018, 2, 28) +
datetime.timedelta(days=1))
24

Además, las fechas no tienen por qué iniciar o terminar dentro de un mismo
mes:

>>> dias_hábiles(datetime.date(2018, 1, 1), datetime.date(2019, 1, 1))
313

313 (que es igual a 365 menos los 52 domingos que hubo en el 2018) sería la
cantidad de días hábiles en ese año (módulo feriados y demás ocasiones no
consideradas ;-)

Saludos,
Germán


El 28 de febrero de 2018, 20:32, Luciano Bovio <omicronvt en gmail.com>
escribió:

> Hola, estoy tratando de encontrar una manera de contar los días hábiles de
> cada mes, puede ser el actual o pasado. Es algo genérico así que son todos
> los días menos los domingos.
> Además tengo que calcular un porcentaje de días transcurridos/sobre días
> hábiles.
>
> Lo más simple que encontré es con numpy:
>
> diashabiles=numpy.busday_count(desde,hasta,weekmask='1111110')
>
> Funciona perfecto excepto que no me cuenta el día de 'fecha
> hasta'(enddates).....
>
> Ejemplo:
> dias=numpy.busday_count(datetime.date(2018,02,01),datetime.
> date.today(),weekmask='1111110')
> da como resultado 23 y necesitaría 24
>
>
> Lo que se me ocurre es sumarle un día a 'fecha hasta' lo cual funciona
> siempre y cuando la 'fecha hasta' no sea domingo, para lo cual tendría que
> chequear si 'fecha hasta' es domingo y restar un día
>
> Que recomiendan ?
>
> Saludos Luciano
> _______________________________________________
> Lista de Correo de PyAr - Python Argentina - pyar en python.org.ar
> Sitio web: http://www.python.org.ar/
>
> Para administrar la lista (o desuscribirse) entrar a
> http://listas.python.org.ar/listinfo/pyar
>
> La lista de PyAr esta Hosteada en USLA - Usuarios de Software Libre de
> Argentina - http://www.usla.org.ar
------------ próxima parte ------------
Se ha borrado un adjunto en formato HTML...
URL: <http://listas.python.org.ar/pipermail/pyar/attachments/20180301/067121d9/attachment.html>


Más información sobre la lista de distribución pyar