python - poner - Cuente el número de días entre fechas, ignorando los fines de semana
python importar fecha (12)
¿Qué pasa con esta solución?
Primero importe el lenguaje de programación Python: Numerical Python (NumPy). Para mayor comodidad lo importamos como ''np''. La función np.busday_count cuenta el número de días válidos entre las fechas de inicio y finalización, sin incluir el día de las fechas de finalización. Si las fechas de finalización especifican un valor de fecha que es anterior al valor de fecha de fechas de inicio correspondiente, el recuento será negativo. Para más información sobre np.busday_count, consulte aquí: https://docs.scipy.org/doc/numpy/reference/generated/numpy.busday_count.html
import numpy as np
np.busday_count(''2018-04-10'', ''2018-04-11'')
Saludos, Yinan
¿Cómo puedo calcular el número de días entre dos fechas que ignoran los fines de semana?
Adapte la respuesta de Dave Webb a una función y agregué algunos casos de prueba:
import datetime
def weekdays_between(start, end):
return sum([1 for daydelta in xrange(1, (end - start).days + 1)
if (start + datetime.timedelta(daydelta)).weekday() < 5])
assert 7 == weekdays_between(
datetime.date(2014,2,19),
datetime.date(2014,3,1))
assert 1 == weekdays_between(
datetime.date(2014,2,19),
datetime.date(2014,2,20))
assert 2 == weekdays_between(
datetime.date(2014,2,19),
datetime.date(2014,2,22))
assert 2 == weekdays_between(
datetime.date(2014,2,19),
datetime.date(2014,2,23))
assert 3 == weekdays_between(
datetime.date(2014,2,19),
datetime.date(2014,2,24))
assert 1 == weekdays_between(
datetime.date(2014,2,21),
datetime.date(2014,2,24))
assert 1 == weekdays_between(
datetime.date(2014,2,22),
datetime.date(2014,2,24))
assert 2 == weekdays_between(
datetime.date(2014,2,23),
datetime.date(2014,2,25))
Creo que la solución más limpia es usar la función busday_count
import numpy as np
import datetime as dt
start = dt.date( 2014, 1, 1 )
end = dt.date( 2014, 1, 16 )
days = np.busday_count( start, end )
Esta es una función que implementé para medir cuántos días laborables tarda el código en integrarse en todas las sucursales. No es necesario iterar durante todos los días intermedios, como lo hacen otras soluciones, sino solo durante la primera semana.
Este problema se puede dividir en dos problemas diferentes:
Cálculo del número de semanas integrales en el intervalo : para una semana integral, el número de días de fin de semana siempre es 2. Esta es una división entera trivial:
(todate - fromdate)/7
Cálculo del número de días de fin de semana en el intervalo restante : esto se puede resolver fácilmente con el enfoque de conteo (map-reduce like):
sum(map(is_weekend, rem_days))
.
def count_working_days(fromdate, todate):
from datetime import timedelta as td
def is_weekend(d): return d.weekday() > 4
# 1st problem
num_weeks = (todate - fromdate).days/7
# 2nd problem
rem_days = (todate - fromdate).days%7
rem_weekend_days = sum(is_weekend(fromdate + td(days=i+1)) for i in range(rem_days))
return (todate - fromdate).days - 2*num_weeks - rem_weekend_days
Y una muestra de su funcionamiento:
>>> for i in range(10): latency(datetime.now(), datetime.now() + timedelta(days=i))
...
0 1 1 1 2 3 4 5 6 6
Intenté las dos respuestas principales (Dave Webb''s y Neil''s) y por alguna razón recibí respuestas incorrectas de ambos. Pudo haber sido un error de mi parte, pero fui con una biblioteca existente sobre la base de que probablemente tenía más funcionalidad y fue mejor probada para casos extremos:
La manera perezosa es pip install workdays
de pip install workdays
para obtener el paquete Python que hace exactamente esto.
Las respuestas dadas hasta ahora funcionarán, pero son muy ineficientes si las fechas están a una gran distancia (debido al ciclo).
Esto debería funcionar:
import datetime
start = datetime.date(2010,1,1)
end = datetime.date(2010,3,31)
daydiff = end.weekday() - start.weekday()
days = ((end-start).days - daydiff) / 7 * 5 + min(daydiff,5) - (max(end.weekday() - 4, 0) % 5)
Esto lo convierte en semanas completas (que tienen 5 días hábiles) y luego se ocupa de los días restantes.
Se corrigió de sábado a domingo el mismo fin de semana para funcionar.
from __future__ import print_function
from datetime import date, timedelta
def workdaycount(startdate,enddate):
if startdate.year != enddate.year:
raise ValueError("Dates to workdaycount must be during same year")
if startdate == enddate:
return int(startdate.weekday() < 5)
elif (enddate - startdate).days == 1 and enddate.weekday() == 6: # Saturday and Sunday same weekend
return 0
first_week_workdays = min(startdate.weekday(), 4) + 1
last_week_workdays = min(enddate.weekday(), 4) + 1
workweeks = int(enddate.strftime(''%W'')) - int(startdate.strftime(''%W''))
return (5 * workweeks) + last_week_workdays - first_week_workdays + 1
for comment, start,end in (
("Two dates same weekend:", date(2010,9,18), date(2010,9,19)),
("Same dates during weekend:", date(2010,9,19), date(2010,9,19)),
("Same dates during week", date(2010,9,16), date(2010,9,16)),
("Dates during same week", date(2010,9,13), date(2010,9,16)),
("Dates during following weeks", date(2010,9,7), date(2010,9,16)),
("Dates after two weeks", date(2010,9,7), date(2010,9,24)),
("Dates from other solution", date(2010,1, 1), date(2010, 3,31))):
daydiff = end.weekday() - start.weekday()
days = ((end-start).days - daydiff) / 7 * 5 + min(daydiff,5)
daygenerator = (start + timedelta(x + 1) for x in xrange((end - start).days))
gendays = sum(day.weekday() < 5 for day in daygenerator)
print(comment,start,end,workdaycount(start,end))
print(''Other formula:'', days, ''. Generator formula: '', gendays)
Tenga en cuenta que el código de @ neil (de lo contrario, excelente) fallará para los intervalos de domingo a jueves. Aquí hay una solución:
def working_days_in_range(from_date, to_date):
from_weekday = from_date.weekday()
to_weekday = to_date.weekday()
# If start date is after Friday, modify it to Monday
if from_weekday > 4:
from_weekday = 0
day_diff = to_weekday - from_weekday
whole_weeks = ((to_date - from_date).days - day_diff) / 7
workdays_in_whole_weeks = whole_weeks * 5
beginning_end_correction = min(day_diff, 5) - (max(to_weekday - 4, 0) % 5)
working_days = workdays_in_whole_weeks + beginning_end_correction
# Final sanity check (i.e. if the entire range is weekends)
return max(0, working_days)
Use este paquete llamado duración del negocio en PyPi.
Código de ejemplo:
from business_duration import businessDuration
import pandas as pd
import datetime
start = pd.to_datetime("2010-1-1 00:00:00")
end = pd.to_datetime("2010-3-31 00:00:00")
businessDuration(startdate=start,enddate=end,unit=''day'')
Fuera [6]: 62.99927083333333
>>> from datetime import date,timedelta
>>> fromdate = date(2010,1,1)
>>> todate = date(2010,3,31)
>>> daygenerator = (fromdate + timedelta(x + 1) for x in xrange((todate - fromdate).days))
>>> sum(1 for day in daygenerator if day.weekday() < 5)
63
Esto crea un generador usando una expresión de generador que producirá la lista de días para llegar desde la fromdate
hasta la fromdate
.
Entonces podríamos crear una lista del generador, filtrando los fines de semana utilizando la función de weekday()
la weekday()
, y el tamaño de la lista indica el número de días que queremos. Sin embargo, para evitar tener toda la lista en la memoria, lo que podría ser un problema si las fechas son muy largas, usamos otra expresión generadora que filtra los fines de semana pero devuelve 1 en lugar de cada fecha. Luego, podemos agregar todos estos 1 juntos para obtener la longitud sin tener que almacenar toda la lista.
Tenga en cuenta que si fromdate == todate
calcule 0 no 1.
import datetime
# some givens
dateB = datetime.date(2010, 8, 31)
dateA = datetime.date(2010, 7, 8)
delta = datetime.timedelta(1)
# number of days
days = 0
while dateB != dateA:
#subtract a day
dateB -= delta
# if not saturday or sunday, add to count
if dateB.isoweekday() not in (6, 7):
days += 1
Creo que algo así debería funcionar. No tengo las herramientas para probarlo ahora mismo.