1

I have been looking at this function for hours and I can't seem to figure out why it is not giving me the result I am expecting. I have a test that generates a datetime start and datetime end. I want to calculate how many 'mondays' or any given day occur between that time range.

def day_count(week_day, start, end):
    if week_day == 1:
        day = 6
    else:
        day = week_day - 2
    num_weekdays, remainder = divmod((end - start).days, 7)
    if (day - start.weekday()) % 7 <= remainder:
        return num_weekdays + 1
    else:
        return num_weekdays

to replicate, this is the data that I give it:

end: 2020-08-22 00:00:00+02:00
start: 2020-08-20 22:15:55.371646+00:00
weekday: 6

I expect to give back num_weekdays = 1

but I get num_weekdays = 0

I have no clue how I can possibly fix this, num_weekdays and remainder are 0 when I debug as well.

This is how i am calling the function:

 total_day_count = day_count(params['dt_start__week_day'], params['dt_start__gte'], params['dt_end__lte'])

and this is how i get the params:

  params = {}
    if self.request.GET.get('day') == 'Today':
        params['dt_start__week_day'] = (timezone.now().weekday() + 1) % 7 + 1
    elif is_valid_queryparam(self.request.GET.get('day')):
        day_of_the_week = self.request.GET.get('day')
        params['dt_start__week_day'] = (int(day_of_the_week) + 1) % 7 + 1
    else:
        params['dt_start__week_day'] = (timezone.now().weekday() + 1) % 7 + 1

    if is_valid_queryparam(self.request.GET.get('date_start')):
        unaware = datetime.strptime(self.request.GET.get('date_start'), '%Y-%m-%d')
        params['dt_start__gte'] = unaware.replace(tzinfo=local_tz)
    else:
        dt = datetime.now().replace(hour=0, minute=0, second=0, microsecond=0)
        first_job = Job.objects.earliest('dt_start')
        params['dt_start__gte'] = first_job.dt_start
    if is_valid_queryparam(self.request.GET.get('date_end')):
        unaware = datetime.strptime(self.request.GET.get('date_end'), '%Y-%m-%d')
        params['dt_end__lte'] = unaware.replace(tzinfo=local_tz) + timedelta(days=1)
    else:
        dt = datetime.now().replace(hour=0, minute=0, second=0, microsecond=0)
        dt_aware = local_tz.localize(dt)
        params['dt_end__lte'] = dt_aware + timedelta(days=1)

I dont know i fthis is helpful, but this is the test:

class MachineDurationViewTestCase(CustomAPITestCase):
"""This testcase contains tests for the API endpoint MachineDurationView """

# todo once views and some of its variables were renamed, also apply these name changes here
fake = Faker()

def setUp(self) -> None:
    self.fake.seed()
    super(MachineDurationViewTestCase, self).setUp()

def test_a_single_job_that_occurs_in_the_space_of_one_hour(self):
    """
    In this test a single job of 30 minutes is created occuring on the first hour on the current date. This means
    that we should expect the endpoint to return an array of 24 value where the first item in the array has a value
    of 0.5 (Because the first hour only occurs 1 time, and job lasts 30 minutes, machine occupancy is 50%)
    """

    dt = timezone.localtime()
    dt_start = dt.replace(hour=0, minute=15)
    dt_end = dt.replace(hour=0, minute=45)
    # dt_end = timezone.datetime(d.year, d.month, d.day, hour=0, minute=45)
    # dt_start = timezone.make_aware(timezone.datetime.now().replace(hour=0, minute=0, second=0, microsecond=0))
    print(dt_start)
    print(dt_end)
    job = JobFactory(dt_start=dt_start, dt_end=dt_end)
    print(job.dt_start)

    # Query the dbase to ensure the job is created
    self.assertEqual(Job.objects.all().count(), 1)

    # Force create/login a user to access the http mocking client
    # (I don't care about authentication or permissions in this test)
    self.client.force_login(user=UserFactory(is_superuser=True))
    response = self.client.get(reverse('data_app:machine_avg'))
    self.assertEqual(response.status_code, 200)
    print(response.data['machines'])
    self.assertNotEqual(response.data['machines'][0], 0.0, "Since we create a job on the first hour, we expect the"
                                                        "first item of the array not to be zero.")
    self.assertEqual(response.data['machines'][0], 0.5, "Since we create a single job of 30 minutes that occurs on "
                                                        "the current date, the value on the given hour should be"
                                                        "0.5 (50% occupancy)")

    # job = JobFactory(dt_start=)
sam
  • 33
  • 4

2 Answers2

0

I believe there's a problem with your input data. This seems to work for me:

from datetime import date

start = date(2020, 8, 20)
end = date(2020, 8, 22)

day_count(6, start, end)

This returns desired output of 1. The type of my dates is: <class 'datetime.date'>

Pieter-Jan
  • 492
  • 4
  • 15
  • you think i should convert the datetime.datetime to datetime.date? I just did start = start.date() to get the date only. it seems to work, but i just feel like this is just a weird work around hehe. – sam Aug 21 '20 at 09:06
  • @sam So it worked? :-) If so, could you mark it as resolved? – Pieter-Jan Aug 21 '20 at 10:59
0

A function that computes the total of a concrete weekday between a date range can be achieved by using the weekday() method of date object:

from datetime import date, timedelta

def days_count(weekdays: list, start: date, end: date):
    dates_diff = end-start
    days = [start + timedelta(days=i) for i in range(dates_diff.days)]
    return len([day for day in days if day.weekday() in weekdays])


start = date(2020, 8, 20)
end = date(2020, 8, 22)
# total of weekend days between that range (end date is excluded)
print(days_count([5, 6], start, end)) # outputs: 0