Created
July 28, 2011 06:47
-
-
Save hmcfletch/1111103 to your computer and use it in GitHub Desktop.
Determine the number of months between two time stamps
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# A direct calculation of the number of months between two dates | |
class Time | |
class << self | |
def months_between(start_date, end_date) | |
return -months_between(end_date, start_date) if end_date < start_date | |
s = start_date | |
t = end_date | |
whole_months = (t.year * 12 + t.month) - (s.year * 12 + s.month) | |
# handle variable length months | |
s_last_day = days_in_month(s.month, s.year) | |
t_last_day = days_in_month(t.month, t.year) | |
if s.day == s_last_day && t.day == t_last_day && s.day >= t.day | |
elsif s.day == s_last_day && t.day == t_last_day && s.day > t.day | |
return whole_months | |
elsif s.day == s_last_day && s.day > t.day | |
return whole_months - 1 | |
elsif s.day == s_last_day && s.day == t.day | |
elsif s.day == s_last_day && s.day < t.day | |
return whole_months | |
elsif t.day == t_last_day && s.day >= t.day | |
elsif t.day == t_last_day && s.day < t.day | |
return whole_months | |
elsif s.day > t.day | |
return whole_months - 1 | |
elsif s.day == t.day | |
elsif s.day < t.day | |
return whole_months | |
end | |
# handle time part | |
[:hour, :min, :sec].each do |part| | |
if s.send(part) > t.send(part) | |
return whole_months - 1 | |
elsif s.send(part) <= t.send(part) | |
return whole_months | |
end | |
end | |
whole_months | |
end | |
end | |
end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# This is a very simple yet potentially inefficient way of determining the months between two dates | |
# The method takes longer the farther the start and end dates are from each other | |
class Time | |
class << self | |
def months_between2(start_date, end_date) | |
return -months_between2(end_date, start_date) if end_date < start_date | |
count = 1 | |
while true | |
return count - 1 if (start_date + count.months) > end_date | |
count += 1 | |
end | |
end | |
end | |
end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# A method with lots of test cases comparing the two methods of calculating the number of months between two dates | |
# The test runs both methods of calculation against the two given dates and compares them. Outputs when there are differences. | |
def self.test_months | |
# a set of start and end date | |
start_dates = [ '2011-02-12', '2011-02-27', '2011-02-28', '2011-03-13', '2011-03-30', '2011-03-31', | |
'2011-04-29', '2011-03-30', '2011-05-30', '2011-05-31' ] | |
end_dates = [ '2011-02-12', '2011-02-14', '2011-04-25', '2011-04-30', '2011-05-17', '2011-05-30', | |
'2011-05-31', '2011-07-25', '2011-07-30', '2011-07-31', '2011-08-05', '2012-02-28', | |
'2012-02-29' ] | |
# a set of times fo append to above dates | |
time_stamps = [ '00:00:00', '00:00:00', '00:00:00', '01:56:23', '04:23:42', '12:04:34', '16:32:03', '22:22:22' ] | |
# a set of start and end dates that proved useful in finding edge cases | |
specials = [ [ '2011-03-31 16:32:03', '2011-07-31 12:04:34' ], | |
[ '2011-03-31 22:22:22', '2012-02-29 12:04:34' ], | |
[ '2011-03-30 22:22:22', '2012-02-29 01:56:23' ], | |
[ '2011-05-31 12:04:34', '2011-07-31 00:00:00' ], | |
[ '2011-02-28 01:56:23', '2012-02-29 00:00:00' ], | |
[ '2011-03-30 22:22:22', '2012-02-29 00:00:00' ], | |
[ '2011-02-28 04:23:42', '2011-07-31 00:00:00' ], | |
[ '2011-02-28 16:32:03', '2011-04-30 00:00:00' ], | |
[ '2011-02-28 16:32:03', '2011-07-31 12:04:34' ], | |
[ '2011-02-28 16:32:03', '2012-02-28 00:00:00' ], | |
[ '2011-03-30 22:22:22', '2012-02-29 04:23:42' ], | |
[ '2011-03-31 16:32:03', '2011-04-30 04:23:42' ], | |
[ '2011-05-31 04:23:42', '2012-02-29 01:56:23' ], | |
[ '2011-03-31 12:04:34', '2011-04-30 04:23:42' ], | |
[ '2011-03-31 01:56:23', '2011-04-30 00:00:00' ], | |
[ '2011-03-31 04:23:42', '2012-02-29 00:00:00' ], | |
[ '2011-05-31 16:32:03', '2012-02-29 01:56:23' ] | |
] | |
# A set of test cases that cover all combinations of: | |
# start_date is last day of the month | |
# end_date is last day of the month | |
# start_date.day <=> end_date.day | |
# start_date.day == end_date.day && start_date.day <=> end_date.day | |
special2 = [ [ '2011-03-31 00:00:00', '2011-04-30 00:00:00' ], # 1 | |
[ '2011-03-31 03:12:43', '2011-05-31 13:32:54' ], # 2 | |
[ '2011-03-31 06:17:23', '2011-05-31 06:17:23' ], # 3 | |
[ '2011-03-31 00:00:00', '2011-05-31 00:00:00' ], # 4 | |
[ '2011-04-30 00:00:00', '2011-05-31 00:00:00' ], # 5 | |
[ '2011-03-31 00:00:00', '2011-06-27 00:00:00' ], # 6 | |
[ '2011-02-28 03:12:43', '2011-07-28 13:32:54' ], # 7 | |
[ '2011-02-28 06:17:23', '2011-07-28 06:17:23' ], # 8 | |
[ '2011-02-28 13:32:54', '2011-07-28 03:12:43' ], # 9 | |
[ '2011-02-28 00:00:00', '2011-05-29 00:00:00' ], # 10 | |
[ '2011-03-30 00:00:00', '2012-02-29 00:00:00' ], # 11 | |
[ '2011-04-30 03:12:43', '2011-06-30 13:32:54' ], # 12 | |
[ '2011-04-30 06:17:23', '2011-06-30 06:17:23' ], # 13 | |
[ '2011-04-30 13:32:54', '2011-06-30 03:12:43' ], # 14 | |
[ '2011-04-30 00:00:00', '2011-07-31 00:00:00' ], # 15 | |
[ '2011-03-17 00:00:00', '2011-07-15 00:00:00' ], # 16 | |
[ '2011-03-17 03:12:43', '2011-08-17 13:32:54' ], # 17 | |
[ '2011-03-17 06:17:23', '2011-08-17 06:17:23' ], # 18 | |
[ '2011-01-17 13:32:54', '2011-07-12 03:12:43' ], # 19 | |
[ '2011-01-17 00:00:00', '2011-07-12 00:00:00' ], # 20 | |
[ '2011-03-12 00:00:00', '2011-09-23 00:00:00' ], # 21 | |
] | |
total_right = 0 | |
total_wrong = 0 | |
start_dates.each do |s| | |
end_dates.each do |e| | |
st = Time.parse("#{s} #{time_stamps[rand(time_stamps.length)]}") | |
et = Time.parse("#{e} #{time_stamps[rand(time_stamps.length)]}") | |
m1 = Time.months_between(st, et) | |
m2 = Time.months_between2(st, et) | |
if m1 != m2 | |
puts "#{st} <=> #{et} :: #{m1} <=> #{m2}" | |
total_wrong += 1 | |
else | |
total_right += 1 | |
end | |
end | |
end | |
puts "-------------------------------" | |
(specials + special2).each do |s| | |
st = Time.parse(s[0]) | |
et = Time.parse(s[1]) | |
m1 = Time.months_between(st, et) | |
m2 = Time.months_between2(st, et) | |
if m1 != m2 | |
puts "#{st} <=> #{et} :: #{m1} <=> #{m2}" | |
total_wrong += 1 | |
else | |
total_right += 1 | |
end | |
end | |
[total_right, total_wrong] | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment