Ruby : Time Math Interview Problem Done Test First
Question from : Blist.com Career Page
# Without using any built in date or time functions, write a function or method
# that accepts two mandatory arguments. The first argument is a string of the
# format "[H]H:MM {AM|PM}" and the second argument is an integer. Assume the
# integer is the number of minutes to add to the string. The return value of
# the function should be a string of the same format as the first argument.
# For example AddMinutes("9:13 AM", 10) would return "9:23 AM". The exercise
# isn't meant to be too hard. I just want to see how you code. Feel free to
# do it procedurally or in an object oriented way, whichever you prefer. Use
# any language you want. Write production quality code.
# Question Source: http://blist.com/blog/
# the following solution was developed using TDD
require 'test/unit'
class TestTimeCalc < Test::Unit::TestCase
def setup
@time = "9:13 AM"
end
def test_new_time_cal
assert_not_nil(TimeCalc.new)
end
def test_add_minute_zero
assert_equal(@time, TimeCalc.add_minutes(@time, 0))
end
def test_add_minute_ten
assert_equal("9:23 AM", TimeCalc.add_minutes(@time, 10))
end
def test_add_minute_thirteen
assert_equal("9:26 AM", TimeCalc.add_minutes(@time, 13))
end
def test_add_hour
assert_equal("10:13 AM", TimeCalc.add_minutes(@time, 60))
end
def test_add_two_hours_fifteen_minutes
assert_equal("11:28 AM", TimeCalc.add_minutes(@time, 135))
end
def test_add_past_meridiem
# 785 minutes = 13 hours and 5 minutes
assert_equal("10:18 PM", TimeCalc.add_minutes(@time, 785))
end
def test_alpha_hour_min_format_throws_exception
assert_raise(ArgumentError) { TimeCalc.add_minutes("AB:CD AM", 10) }
end
def test_bad_meridiem_throws_exception
assert_raise(ArgumentError) { TimeCalc.add_minutes("AB:CD TM", 10) }
end
def test_hr_greater_than_twelve
assert_raise(ArgumentError) { TimeCalc.add_minutes("13:00 PM", 10) }
end
def test_min_greater_than_fifty_nine
assert_raise(ArgumentError) { TimeCalc.add_minutes("12:60 PM", 10) }
end
end # end class TestTimeCalc
class TimeCalc
def self.add_minutes(time, minutes)
(hour, min, meridiem) = parse_time_string(time)
hour_increment = (min + minutes)/60
min_increment = (min + minutes)%60 - min
if (hour_increment >= 12)
meridiem = (meridiem == 'AM' ? 'PM' : 'AM')
hour_increment -= 12
end
hour += hour_increment
min += min_increment
hour.to_s + ":" + min.to_s + " " + meridiem
end
private
def self.parse_time_string(time)
raise ArgumentError unless (matches = time.match(/(\d{1,2}):(\d{1,2})\s+(\w{2})/))
matches = time.match(/^(\d{1,2}):(\d{1,2})\s+([A|P]M)$/)
hour = matches[1].to_i
min = matches[2].to_i
meridiem = matches[3]
raise ArgumentError unless (hour <= 12)
raise ArgumentError unless (min < 60)
return [hour, min, meridiem]
end
end # end class TimeCalc
Nice work. Unfortunately, I am not as mathematically inclined as you are. My solution would have been far less impressive but I will try to code it and post it here, if possible.
Arsalan
December 29, 2007 at 3:53 am
Couldn’t figure how to post serious html on the blog (to post source code)! After hacking a large part of the night, I have the code tested and ready. Here it is: http://saaraydost.blogspot.com/
Arsalan
December 30, 2007 at 9:48 am
I have posted the new solution with the rounding-off bug fix to my new blog: http://softwareworks.wordpress.com/
Arsalan
January 2, 2008 at 4:21 am