Very nice piece of code Rick! I'm a Ruby newbee and I find it facinating
when I see code that applies better the "Ruby Way". Thanks for sharing.
I borrow parts of your code and rewrote the method I sent:
class Date
def elapsedYearsAndDays(rangeDate)
startDate, endDate = *(self >= rangeDate ? [rangeDate, self] :
[self, rangeDate])
#This is the real problem: Febraury 29th!
isMagicDate = (startDate.month == 2) && (startDate.day == 29)
startDate += 1 if !endDate.leap? && isMagicDate
elapsedYears = endDate.year - startDate.year
previousStartDate = Date.new(endDate.year, startDate.month,
startDate.day)
if endDate < previousStartDate
elapsedYears -= 1
previousStartDate = Date.new(endDate.year - 1, startDate.month,
startDate.day)
previousStartDate -= 1 if previousStartDate.leap? && isMagicDate
end
return elapsedYears, endDate - previousStartDate
end
end
startDates = [Date.today,
Date.new(1963, 11, 22),
Date.new(2007, 3, 1),
Date.new(2004, 3, 1),
Date.new(2004, 2, 29),
Date.new(2004, 3, 1),
Date.new(2004, 2, 29),
Date.new(2007,3,15),
Date.new(2000,3,14)]
endDates = [Date.new(1963, 11, 22),
Date.new(1963, 11, 22),
Date.new(2004, 3, 1),
Date.new(2001, 3, 2),
Date.new(2001, 3, 1),
Date.new(2001, 3, 1),
Date.new(2009, 3, 1),
Date.new(2000,3,14),
Date.new(2007,3,15)]
startDates.each_with_index do |startDate, index|
elapsedYears, elapsedDays =
startDate.elapsedYearsAndDays(endDates[index])
daysMessage = (elapsedDays > 0) ? (" and #{elapsedDays} day(s)") : ''
puts "Start date: #{startDate} End date: #{endDates[index]}"
puts "Elapsed time: #{elapsedYears} year(s)#{daysMessage}\n\n"
end
=begin
---------------------------------------------------------------------------
At the same time I took your code and added the same test dates I used:
=end
require 'date'
class Date
# return the number of days since the beginning of the year
def years_since(date)
# The parens in the expression below aren't strictly necessary, but
# I think it makes what's going on a little bit clearer.
first, last = *(self >= date ? [date, self] : [self, date])
(self <=> date) * ((last.year - first.year) - (first.yday >
last.yday ? 1 : 0))
end
end
startDates = [Date.today,
Date.new(1963, 11, 22),
Date.new(2007, 3, 1),
Date.new(2004, 3, 1),
Date.new(2004, 2, 29),
Date.new(2004, 3, 1),
Date.new(2004, 2, 29),
Date.new(2007,3,15),
Date.new(2000,3,14)]
endDates = [Date.new(1963, 11, 22),
Date.new(1963, 11, 22),
Date.new(2004, 3, 1),
Date.new(2001, 3, 2),
Date.new(2001, 3, 1),
Date.new(2001, 3, 1),
Date.new(2009, 3, 1),
Date.new(2000,3,14),
Date.new(2007,3,15)]
startDates.each_with_index do |startDate, index|
elapsedYears = startDate.years_since(endDates[index])
puts "Start date: #{startDate} End date: #{endDates[index]}"
puts "Elapsed time: #{elapsedYears} year(s)\n\n"
end
=begin
As you can see from the results, both pieces of code give the same
results
except when a leap year is involved. I think my version is correct in
those cases
![Smile :) :)](data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7)
because we don't want to say that a complete year has
passed until that is totally true.
Regards,
Nando
=end