Skip to content

Commit

Permalink
allowed decimal format for hours, this resolves #1
Browse files Browse the repository at this point in the history
  • Loading branch information
ldgit committed Dec 12, 2015
1 parent f05dbc3 commit fd6aa4e
Show file tree
Hide file tree
Showing 4 changed files with 46 additions and 19 deletions.
5 changes: 5 additions & 0 deletions app/decimal_notation_strategy.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
class DecimalNotationStrategy:
def calculate_minutes(self, decimal_notation_string):
decimal_hour = float(decimal_notation_string)

return int(decimal_hour * 60)
14 changes: 14 additions & 0 deletions app/hour_notation_strategy.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
class HourNotationStrategy:
def calculate_minutes(self, hour_notation_string):
change_sign = False
if hour_notation_string.startswith('-'):
hour_notation_string = hour_notation_string[1:]
change_sign = True

time_list = hour_notation_string.split(':')
hours = int(time_list[0])
minutes = int(time_list[1])

total_minutes = minutes + hours * 60

return -total_minutes if change_sign else total_minutes
22 changes: 8 additions & 14 deletions app/hours_calculator.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
from __future__ import division
import re
from .hour_notation_strategy import HourNotationStrategy
from .decimal_notation_strategy import DecimalNotationStrategy


class HoursCalculator:
Expand All @@ -16,7 +18,7 @@ def add(self, *args):
continue
if not self._is_valid_format(hour):
return 'Invalid hour value: "{0}"'.format(hour)
total_minutes += self._calculate_total_minutes_from_string(hour.replace('.', ':'))
total_minutes += self._get_calculation_strategy(hour).calculate_minutes(hour)

total_hours = int(total_minutes / 60)
remaining_minutes = abs(total_minutes) % 60
Expand All @@ -26,19 +28,11 @@ def add(self, *args):

return '{0:02d}:{1:02d}'.format(total_hours, remaining_minutes)

def _calculate_total_minutes_from_string(self, time_string):
change_sign = False
if time_string.startswith('-'):
time_string = time_string[1:]
change_sign = True

time_list = time_string.split(':')
hours = int(time_list[0])
minutes = int(time_list[1])

total_minutes = minutes + hours * 60

return -total_minutes if change_sign else total_minutes
def _get_calculation_strategy(self, time_string):
if ':' in time_string:
return HourNotationStrategy()
else:
return DecimalNotationStrategy()

def _is_valid_format(self, hour):
pattern = re.compile('^\s*[+-]?\d+[.:]\d+\s*$')
Expand Down
24 changes: 19 additions & 5 deletions tests/test_hours_calculator.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ def test_add_with_no_parameters_returns_zero(self):
def test_add_with_one_parameter_returns_that_parameter(self):
self.assertEqual("02:53", self.calculator.add("2:53"))

def test_add_replace_dot_with_colon(self):
self.assertEqual("02:53", self.calculator.add("2.53"))
# def test_add_replace_dot_with_colon(self):
# self.assertEqual("02:53", self.calculator.add("2.53"))

def test_add_ignore_leading_zero(self):
self.assertEqual("02:53", self.calculator.add("02:53"))
Expand All @@ -40,7 +40,7 @@ def test_add_two_time_values(self):
self.assertEqual("01:15", self.calculator.add("1:15", "0:00"))
self.assertEqual("02:15", self.calculator.add("1:15", "1:00"))
self.assertEqual("03:15", self.calculator.add("1:15", "1:60"))
self.assertEqual("04:15", self.calculator.add("1:75", "01.60"))
self.assertEqual("04:15", self.calculator.add("1:75", "01:60"))

def test_add_multiple_time_values(self):
self.assertEqual("07:10", self.calculator.add("1:50", "2:35", "2:45"))
Expand All @@ -60,7 +60,7 @@ def test_add_positive_with_negative_hours(self):

def test_add_multiple_negative_hours(self):
self.assertEqual("-2:10", self.calculator.add("-1:10", "-1:00"))
self.assertEqual("-3:40", self.calculator.add("-1:10", "-1:00", "-1.30"))
self.assertEqual("-3:40", self.calculator.add("-1:10", "-1:00", "-1:30"))

def test_large_hours_and_minutes(self):
self.assertEqual("113:35", self.calculator.add("111:155"))
Expand All @@ -76,8 +76,22 @@ def test_ignore_blank_spaces_arround_hour_strings(self):
def test_input_hours_as_array(self):
self.assertEqual("-1:20", self.calculator.add(*[u'1:00', u'-2:20']))

def test_decimal_inputs(self):
self.assertEqual("01:30", self.calculator.add("1.5"))
self.assertEqual("01:12", self.calculator.add("1.2"))
self.assertEqual("04:42", self.calculator.add("4.7"))
self.assertEqual("02:42", self.calculator.add("1.2", "1.5"))

def test_negative_decimal_inputs(self):
self.assertEqual("-4:42", self.calculator.add("-4.7"))
self.assertEqual("-00:18", self.calculator.add("1.2", "-1.5"))

def test_round_down_decimal_inputs(self):
self.assertEqual("00:58", self.calculator.add("0.97"))
self.assertEqual("00:13", self.calculator.add("0.23"))

def test_integration(self):
self.assertEqual("05:00", self.calculator.add("1:65", "-1.00", '4.70', '-0.75'))
self.assertEqual("05:02", self.calculator.add("1:65", "-1.00", '4.70', '-0.75'))

def test_invalid_inputs_return_NaN_string(self):
self.assertEqual("Invalid hour value: \"1:1:65\"", self.calculator.add("1:1:65"))
Expand Down

0 comments on commit fd6aa4e

Please sign in to comment.