mirror of
https://github.com/nikdoof/businesshours.git
synced 2025-12-13 13:12:15 +00:00
Initial import.
This commit is contained in:
4
.gitignore
vendored
Normal file
4
.gitignore
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
.idea
|
||||
.pyc
|
||||
build/
|
||||
dist/
|
||||
1
businesshours/__init__.py
Normal file
1
businesshours/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
from .core import calc_business_hours
|
||||
50
businesshours/core.py
Normal file
50
businesshours/core.py
Normal file
@@ -0,0 +1,50 @@
|
||||
from datetime import datetime, timedelta, time
|
||||
|
||||
|
||||
def calc_business_hours(start, end, weekdays=(1, 2, 3, 4, 5), hours=range(8, 18)):
|
||||
"""Calculates the number of seconds hours between two dates"""
|
||||
|
||||
def date_range(start_date, end_date):
|
||||
"""Converts two datetimes into a list of dates between them"""
|
||||
if isinstance(start_date, datetime):
|
||||
start_date = start_date.date()
|
||||
if isinstance(end_date, datetime):
|
||||
end_date = end_date.date()
|
||||
if start_date > end_date:
|
||||
raise ValueError('You provided a start_date that comes after the end_date.')
|
||||
while True:
|
||||
yield start_date
|
||||
start_date = start_date + timedelta(days=1)
|
||||
if start_date > end_date:
|
||||
break
|
||||
|
||||
if start.date() == end.date():
|
||||
if not start.date().isoweekday() in weekdays:
|
||||
return 0
|
||||
if start.time().hour in hours:
|
||||
actual_start = start
|
||||
else:
|
||||
if start.time().hour >= hours[-1] + 1:
|
||||
return 0
|
||||
actual_start = datetime.combine(start.date(), time(hours[0], 0, 0))
|
||||
if end.time().hour in hours:
|
||||
actual_end = end
|
||||
else:
|
||||
if end.time().hour <= hours[0]:
|
||||
return 0
|
||||
actual_end = datetime.combine(end.date(), time(hours[-1] + 1, 0, 0))
|
||||
secs = (actual_end - actual_start).total_seconds()
|
||||
return secs
|
||||
else:
|
||||
total_seconds = 0
|
||||
dates = [dt for dt in date_range(start, end)]
|
||||
|
||||
for idx, dt in enumerate(dates):
|
||||
day_start = datetime.combine(dt, time(0, 0, 0))
|
||||
day_end = datetime.combine(dt, time(23, 59, 59))
|
||||
if idx == 0:
|
||||
day_start = start
|
||||
if idx == len(dates) - 1:
|
||||
day_end = end
|
||||
total_seconds += calc_business_hours(day_start, day_end, weekdays, hours)
|
||||
return total_seconds
|
||||
1
businesshours/tests/__init__.py
Normal file
1
businesshours/tests/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
__author__ = 'nikdoof'
|
||||
36
businesshours/tests/test_core.py
Normal file
36
businesshours/tests/test_core.py
Normal file
@@ -0,0 +1,36 @@
|
||||
from datetime import datetime
|
||||
import unittest
|
||||
|
||||
from businesshours import calc_business_hours
|
||||
|
||||
|
||||
class TestCalcBusinessHours(unittest.TestCase):
|
||||
|
||||
def run_tests(self, tests):
|
||||
for res, dt1, dt2 in tests:
|
||||
self.assertEqual(calc_business_hours(dt1, dt2,), res)
|
||||
|
||||
def test_invalid_arguments(self):
|
||||
self.assertRaises(ValueError, calc_business_hours, datetime(2014,1,2), datetime(2014,1,1))
|
||||
|
||||
def test_simple_day(self):
|
||||
self.run_tests([
|
||||
(60, datetime(2013, 8, 1, 9, 0, 0), datetime(2013, 8, 1, 9, 1, 0)),
|
||||
(600, datetime(2013, 8, 1, 9, 0, 0), datetime(2013, 8, 1, 9, 10, 0)), # Simple multiday
|
||||
(36000, datetime(2013, 8, 1, 9, 0, 0), datetime(2013, 8, 2, 9, 0, 0)),
|
||||
(72000, datetime(2013, 8, 5, 9, 0, 0), datetime(2013, 8, 7, 9, 0, 0)),
|
||||
])
|
||||
|
||||
def test_multiday_out_of_hours(self):
|
||||
self.run_tests([
|
||||
(68400, datetime(2013, 8, 5, 9, 0, 0), datetime(2013, 8, 7, 0, 1, 0)),
|
||||
(72000, datetime(2013, 8, 5, 7, 0, 0), datetime(2013, 8, 7, 8, 0, 0)),
|
||||
(72000, datetime(2013, 8, 5, 6, 0, 0), datetime(2013, 8, 7, 8, 0, 0)),
|
||||
])
|
||||
|
||||
def test_weekend_single_day(self):
|
||||
self.run_tests([
|
||||
(0, datetime(2013, 8, 24, 9, 0, 0), datetime(2013, 8, 24, 9, 1, 0)),
|
||||
(0, datetime(2013, 8, 25, 9, 0, 0), datetime(2013, 8, 25, 9, 10, 0)), # Multiday during weekend
|
||||
(0, datetime(2013, 8, 3, 7, 0, 0), datetime(2013, 8, 4, 9, 0, 0)),
|
||||
])
|
||||
Reference in New Issue
Block a user