I have a feeling there is a simple/built-in way to do this but I can\'t find it.
I have a duration (in seconds) in an integer and I want to display it in a friendly form
hours = 3.5456
value = (hours*60).divmod(60).map{ |a| "%02d"%[a.floor] }.join(":")
=> "03:32"
ActiveSupport::Duration.build
+ inspect
gives you valid results
>> ActiveSupport::Duration.build(125557).inspect
=> "1 day, 10 hours, 52 minutes, and 37 seconds"
I guess you could do also something like:
(Time.mktime(0)+3600).strftime("%H:%M:%S")
To format it as you wish.
BTW, originally I thought of using Time.at() but seems that EPOCH time on my Ubuntu is Thu Jan 01 01:00:00 +0100 1970 and not 00:00:00 hours as I expected, and therefore if I do:
Time.at(3600).strftime("%H:%M:%S")
Gives me 1 hour more than wanted.
See: http://api.rubyonrails.org/classes/ActionView/Helpers/DateHelper.html
distance_of_time_in_words(3600)
=> "about 1 hour"
Shout out to @joshuapinter who gave the best answer (in the form of a comment).
Use the drop-in replacement dotiw
gem to gain more control over the accuracy of the output to suit different needs:
https://github.com/radar/distance_of_time_in_words
Sample view code:
%label
Logoff after:
- expire_in = distance_of_time_in_words(Time.now, Time.now + user.custom_timeout.minutes, :only => [:minutes, :hours, :days])
= expire_in
Resulting in something like this:
Logoff after: 1 day, 13 hours, and 20 minutes
This one uses the obscure divmod
method to divide and modulo at the same time, so it handles Float
seconds properly:
def duration(seconds)
minutes, seconds = seconds.divmod(60)
hours, minutes = minutes.divmod(60)
days, hours = hours.divmod(24)
"#{days.to_s.rjust(3)}d #{hours.to_s.rjust(2)}h #{minutes.to_s.rjust(2)}m #{seconds}s"
end