2010-02-08 97 views
47

Necesito restar días hábiles a partir de la fecha actual.Días hábiles en Python

Actualmente tengo un código que siempre se debe ejecutar en el día hábil más reciente. Así que eso puede ser hoy si estamos de lunes a viernes, pero si es sábado o domingo, entonces tengo que volver al viernes antes del fin de semana. En este momento tengo algunos bastante torpe código para hacer esto:

lastBusDay = datetime.datetime.today() 
if datetime.date.weekday(lastBusDay) == 5:  #if it's Saturday 
    lastBusDay = lastBusDay - datetime.timedelta(days = 1) #then make it Friday 
elif datetime.date.weekday(lastBusDay) == 6:  #if it's Sunday 
    lastBusDay = lastBusDay - datetime.timedelta(days = 2); #then make it Friday 

¿Hay una mejor manera?

¿Puedo decirle a timedelta que trabaje en días de la semana en lugar de días del calendario, por ejemplo?

+5

¿Qué pasa con las vacaciones? – SLaks

+0

Sí, ya me estoy ocupando de eso: mi base de datos siempre llena vacaciones siempre que caigan en un día laborable. Pero estoy de acuerdo, las vacaciones en general también son un problema. Quiero decir que podría empezar a ser elegante y usar los sckits.timeseries, pero realmente quiero algo más simple. –

+0

Aquí hay un fragmento de Dzzone que podría ayudarte: http://snippets.dzone.com/posts/show/9173 –

Respuesta

76

Use pandas!

import pandas as pd 
# BDay is business day, not birthday... 
from pandas.tseries.offsets import BDay 

# pd.datetime is an alias for datetime.datetime 
today = pd.datetime.today() 
print today - BDay(4) 

Como hoy es el jueves, Sept 26, que le dará una producción de:

datetime.datetime(2013, 9, 20, 14, 8, 4, 89761) 
+2

Agradable. esa es la respuesta correcta, hoy. Cuando pregunté Q, los pandas todavía estaban un poco incompletos. –

+3

La versión más reciente de pandas (0.14.0) también admite calendarios de vacaciones – fantabolous

12

Parece que hay varias opciones si está abierto a la instalación de bibliotecas adicionales.

En esta publicación se describe una forma de definir días laborables con dateutil.

http://coding.derkeiler.com/Archive/Python/comp.lang.python/2004-09/3758.html

businesshours le permite a medida define su lista de vacaciones, etc., para definir cuando sus horas de trabajo (y por extensión días laborables) son.

http://pypi.python.org/pypi/BusinessHours/

+0

nice one Alison. Todavía no es muy simple, aunque desafortunadamente. Aunque voy a seguir tu ruta. Gracias por la ayuda. –

+1

Definir días hábiles en todas las culturas es poco probable que sea un problema lo suficientemente simple como para incluirse en la biblioteca estándar. –

+2

Un punto válido, como de hecho mi aplicación es para los mercados financieros, y Egipto e Israel están abiertos los domingos. –

6

Tal vez este código podría ayudar:

lastBusDay = datetime.datetime.today() 
shift = datetime.timedelta(max(1,(lastBusDay.weekday() + 6) % 7 - 3)) 
lastBusDay = lastBusDay - shift 

La idea es que los lunes yo tienen que volver 3 días, los domingos 2 y 1 en cualquier otro día.

La declaración (lastBusDay.weekday() + 6) % 7 acaba de volver a las bases del lunes de 0 a 6.

Realmente no sé si esto va a ser mejor en términos de rendimiento.

0

¿Por qué no intentar algo como:

lastBusDay = datetime.datetime.today() 
if datetime.date.weekday(lastBusDay) not in range(0,5): 
    lastBusDay = 5 
0
def getNthBusinessDay(startDate, businessDaysInBetween): 
    currentDate = startDate 
    daysToAdd = businessDaysInBetween 
    while daysToAdd > 0: 
     currentDate += relativedelta(days=1) 
     day = currentDate.weekday() 
     if day < 5: 
      daysToAdd -= 1 

    return currentDate 
9

Disclamer: Soy el autor ...

I escribió un paquete que hace exactamente esto, cálculos de fechas comerciales. Puede usar la especificación de la semana personalizada y días festivos.

Tuve este problema exacto al trabajar con datos financieros y no encontré ninguna de las soluciones disponibles particularmente fácil, así que escribí una.

Espero que esto sea útil para otras personas.

https://pypi.python.org/pypi/business_calendar/

+1

muchas gracias, su biblioteca funcionó perfectamente para mí. Tal vez deberías agregar en tu documentación que tu biblioteca admite días negativos si quieres restar días, y que está en el pip – guinunez

+0

Oye, sé que esta podría no ser la mejor manera de contactarte pero solo quería informar un problema Estaba teniendo tu módulo business_calendar. Configuré un calendario con feriados federales en EE. UU .: ['2015-01-01', '2015-01-19', '2015-02-16', '2015-05-25', '2015-07- 03 ',' 2015-09-07 ', ' 2015-10-12 ',' 2015-11-11 ', ' 2015-11-26 ',' 2015-12-25 '] luego trataron de calcular el diferencia entre fecha y hora (2015, 1, 16, 15, 28, 40) y fecha y hora (2015, 1, 23, 11, 58, 0) pero devuelve constantemente -1. Eliminando h/m/s de los resultados de fecha y hora (correctamente) en 4. –

+1

En realidad, al realizar otras pruebas, ciertas comparaciones de fechas simplemente se bloquean, sin razón aparente, sin parecer que nunca se devuelve un resultado. En mi ejemplo anterior, el intento de comparar fecha y hora (2015, 1, 16) con fecha y hora (2015, 1, 25) conduce a dicho bloque, con o sin establecer explícitamente las vacaciones. Tras la investigación, esto ocurre cuando el parámetro date2 pasa a ser una fecha que no es un día de trabajo. –

2

Esto le dará un generador de días de trabajo, por supuesto, sin vacaciones, parada es datetime.datetime objeto. Si necesita vacaciones a la hacen argumento adicional con la lista de las vacaciones y comprobar con 'IFology' ;-)

def workingdays(stop, start=datetime.date.today()): 
    while start != stop: 
     if start.weekday() < 5: 
      yield start 
     start += datetime.timedelta(1) 

Más adelante se puede contar con ellos como

workdays = workingdays(datetime.datetime(2015, 8, 8)) 
len(list(workdays)) 
Cuestiones relacionadas