Saari Development

This blog is intended to be a log of my (Ali Rizvi's) professional ramblings as a software development engineer. I intend to add logs of my experience with different technologies, software, tech books/articles and related stuff from time to time. My intention is to have an archive for my personal use and public benefit.

Friday, December 28, 2007

Ruby : Time Math Interview Problem Done Test First

Question from : Blist.com Career Page

1 # Without using any built in date or time functions, write a function or method
2 # that accepts two mandatory arguments. The first argument is a string of the
3 # format "[H]H:MM {AM|PM}" and the second argument is an integer. Assume the
4 # integer is the number of minutes to add to the string. The return value of
5 # the function should be a string of the same format as the first argument.
6 # For example AddMinutes("9:13 AM", 10) would return "9:23 AM". The exercise
7 # isn't meant to be too hard. I just want to see how you code. Feel free to
8 # do it procedurally or in an object oriented way, whichever you prefer. Use
9 # any language you want. Write production quality code.
10 # Question Source: http://blist.com/blog/
11
12 # the following solution was developed using TDD
13
14 require 'test/unit'
15
16 class TestTimeCalc < Test::Unit::TestCase
17
18 def setup
19 @time = "9:13 AM"
20 end
21
22 def test_new_time_cal
23 assert_not_nil(TimeCalc.new)
24 end
25
26 def test_add_minute_zero
27 assert_equal(@time, TimeCalc.add_minutes(@time, 0))
28 end
29
30 def test_add_minute_ten
31 assert_equal("9:23 AM", TimeCalc.add_minutes(@time, 10))
32 end
33
34 def test_add_minute_thirteen
35 assert_equal("9:26 AM", TimeCalc.add_minutes(@time, 13))
36 end
37
38 def test_add_hour
39 assert_equal("10:13 AM", TimeCalc.add_minutes(@time, 60))
40 end
41
42 def test_add_two_hours_fifteen_minutes
43 assert_equal("11:28 AM", TimeCalc.add_minutes(@time, 135))
44 end
45
46 def test_add_past_meridiem
47 # 785 minutes = 13 hours and 5 minutes
48 assert_equal("10:18 PM", TimeCalc.add_minutes(@time, 785))
49 end
50
51 def test_alpha_hour_min_format_throws_exception
52 assert_raise(ArgumentError) { TimeCalc.add_minutes("AB:CD AM", 10) }
53 end
54
55 def test_bad_meridiem_throws_exception
56 assert_raise(ArgumentError) { TimeCalc.add_minutes("AB:CD TM", 10) }
57 end
58
59 def test_hr_greater_than_twelve
60 assert_raise(ArgumentError) { TimeCalc.add_minutes("13:00 PM", 10) }
61 end
62
63 def test_min_greater_than_fifty_nine
64 assert_raise(ArgumentError) { TimeCalc.add_minutes("12:60 PM", 10) }
65 end
66
67 end # end class TestTimeCalc
68
69 class TimeCalc
70
71 def self.add_minutes(time, minutes)
72 (hour, min, meridiem) = parse_time_string(time)
73
74 hour_increment = (min + minutes)/60
75 min_increment = (min + minutes)%60 - min
76 if (hour_increment >= 12)
77 meridiem = (meridiem == 'AM' ? 'PM' : 'AM')
78 hour_increment -= 12
79 end
80
81 hour += hour_increment
82 min += min_increment
83
84 hour.to_s + ":" + min.to_s + " " + meridiem
85 end
86
87 private
88
89 def self.parse_time_string(time)
90 raise ArgumentError unless (matches = time.match(/(\d{1,2}):(\d{1,2})\s+(\w{2})/))
91 matches = time.match(/^(\d{1,2}):(\d{1,2})\s+([A|P]M)$/)
92 hour = matches[1].to_i
93 min = matches[2].to_i
94 meridiem = matches[3]
95 raise ArgumentError unless (hour <= 12)
96 raise ArgumentError unless (min < 60)
97 return [hour, min, meridiem]
98 end
99
100 end # end class TimeCalc

3 Comments:

Blogger Arsalan said...

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.

7:53 PM  
Blogger Arsalan said...

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/

1:48 AM  
Blogger Arsalan said...

I have posted the new solution with the rounding-off bug fix to my new blog: http://softwareworks.wordpress.com/

8:21 PM  

Post a Comment

<< Home