Daniel Rosenthal
Daniel Rosenthal

Reputation: 1386

Business days in Django

I need to implement a conditional break which uses business days. I have a class with a DateField, and if that date is less than 5 business days in the future, something (action a) happens, else b happens. How can I determine the number of business days between two objects?

Obviously I'll need to calculate what 5 business days from today is. Finding 5 days in the future would be easy, using a simple time-delta, but to account for business days, it gets more complicated. I think I can safely ignore holidays for now (it's not the best case, but I think I can make due with just having Business days be Monday-Friday). Can anyone give me some guidance as to how I could do something like: target = today + 5 business_days?

Thanks

Upvotes: 2

Views: 2849

Answers (2)

Philip Mutua
Philip Mutua

Reputation: 6891

This Example is when you are making a django project as an API

You can get business days with Numpy which uses SCIPY(check for more details) You will have to install numpy through pip

Python 2.7

pip install numpy

Python 3

pip3 install numpy

In models.py add depending on where you want to put your property method :

class WorkingDay(models.Model):
    # YY-MM-DD
    start = models.DateField(null=True, verbose_name="start")
    end = models.DateField(null=True, verbose_name="end")
@property
def workdays(self):

    total = np.busday_count(self.start, self.end)

    return total

Then in your serializers.py you might have something like this.

class WorkingDaySerializer(serializers.ModelSerializer):

    workdays = serializers.IntegerField(read_only=True)

    class Meta:
        model = WorkingDay
        fields = '__all__'
        read_only_fields = ['workdays']

In your views you might do something like this.

class WorkingDayAPI(APIView):

    """
    {   "start":"2018-01-01",
        "end":"2018-05-01"
    }
    GET work days between dates 
    """

    serializer_class = WorkingDaySerializer

    def get(self, request, format=None):
        business_days = WorkingDay.objects.all()
        serializer = WorkingDaySerializer(business_days, many=True)
        return Response(serializer.data)

    def post(self, request, *args, **kwargs):
        start = request.data.get('start')
        end = request.data.get('end')

        # bizdays = request.data.get('bizdays')

        business_days = WorkingDay.objects.create(**request.data)
        business_days.start = start
        business_days.end = end
        business_days.workdays = workdays
        business_days.save()
        serializer = WorkingDaySerializer(business_days)
        return Response(serializer.data, status=status.HTTP_201_CREATED)

Upvotes: 0

Thomas
Thomas

Reputation: 11888

Here's a generic solution, even though your case is embarrassingly simple ;P

from datetime import timedelta, date

def add_business_days(from_date, number_of_days):
    to_date = from_date
    while number_of_days:
       to_date += timedelta(1)
       if to_date.weekday() < 5: # i.e. is not saturday or sunday
           number_of_days -= 1
    return to_date

And the result.

>>> date.today()
datetime.date(2013, 7, 25)
>>> add_business_days(date.today(), 6)
datetime.date(2013, 8, 2)

Bonus marks if you check whether a date falls on a holiday in the if statement.

Upvotes: 4

Related Questions