Sylar Sylar - 24 days ago 8
Ruby Question

Calculate total hours in Rails

Foo.first = {id: 1, start:2000-01-01 07:00:00 UTC, end: 2000-01-01 12:00:00 UTC, total_hours_worked: nil}


end
is used as an example here.


I've created
Foo
with
t.time
for both
start
and
end
as I only needed hours/min. I've never worked with Time objects before so bear with me.

I need to get the total hours with minutes with
start
and
end
:

start = Foo.find(1).start
end = Foo.find(1).end
start + end #=> errors
start.to_i + end.to_i = 1893438000 #=> What's that?
distance_of_time_in_words(start.to_i + end.to_i) #=> "about 60 years" What?


Im expecting
5:00:00
. Im aware that
5:00:00
really means 5am but the context will used different.

Doing few searches I've seen this. I'm really trying not to use more gems for this "should have baked in method" in Rails/Ruby.

My question will find an answer to what I'm really trying to achieve (get total of hours worked for the week):

Foo.pluck(:total_hours_worked).sum(&:to_d) #=> best way?


Where
:total_hours_worked
would be a string, just to make things less complicated.

Answer

Here is how you'd get the format you want ("5:00:00"):

# Monkeypatch Integer class to add a new method
class Integer
  def pretty_duration
    seconds = self % 60
    minutes = (self / 60) % 60
    hours   = self / (60 * 60)

    format('%02d:%02d:%02d', hours, minutes, seconds)
  end
end

# Get start and end time converted into integers
timestart = (Time.now - 5.hours).to_i
timeend   = Time.now.to_i

# Use pretty_duration method.
# P.S. Difference between time objects already gives you a number, but we need Integer
(timeend - timestart).pretty_duration
#=> "05:00:00"

This setup allows you not to be reliant on Rails view helpers (distance_of_time_in_words), because you might be in need to have time formatted somewhere beyond the view.

My question will find an answer to what I'm really trying to achieve (get total of hours worked for the week):

Foo.pluck(:total_hours_worked).sum(&:to_d) #=> best way? Where :total_hours_worked would be a string, just to make things less complicated.

The most efficient way (if you settle with having total_hours_worked as string of correct format) would be summing it up having casted to decimal on the db level:

Foo.sum('total_hours_worked::decimal')
Comments