Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Calculate average number of days between datetimes in Ruby

I want to take a list of datetimes in Ruby and then calculate the number of days between them and then average those dates. Is this correct? Is there a shorter way to do this?

dates = ["2012-08-05 00:00:00 UTC", "2012-06-17 00:00:00 UTC", "2012-06-15 00:00:00 UTC", "2011-06-06 00:00:00 UTC"]

difference = Array.new

dates.each_with_index do |date, index|
    if index != 0
        difference << date.to_date - dates[index - 1].to_date
    end
end

avg = difference.inject{ |sum, el| sum + el }.to_f / arr.size

And then would that output it in days format?

You can give me a Rails version as well if you'd like as I'll be pulling the datetimes from a model field.

like image 637
user2270029 Avatar asked Mar 20 '23 18:03

user2270029


1 Answers

I think you have an off-by-one problem. If you have n values in dates then you'll have n-1 differences between consecutive pairs so your avg should be:

avg = difference.inject{ |sum, el| sum + el }.to_f / (arr.size - 1)

And your inject is just a long winded way of saying inject(:+) so you could say:

avg = difference.inject(:+).to_f / (arr.size - 1)

In any case, you could use map and each_cons to make it a bit nicer:

dates.map(&:to_date).each_cons(2).map { |d1, d2| d1 - d2 }.inject(:+) / (dates.length - 1)

First we can convert everything to dates in one pass with map(&:to_date) rather than converting every time we need a date instead of a string. Then the each_cons(2) iterates over the array in consecutive pairs (i.e. [1,2,3,4] is iterated as [[1,2], [2,3], [3,4]]). Then a simple map to get the differences between the pairs and inject(:+) to add them all up.

The above will leave you with a Rational but you can to_f or to_i that if you need a floating point or integer value.

like image 76
mu is too short Avatar answered Mar 23 '23 12:03

mu is too short