Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

how to convert 270921sec into days + hours + minutes + sec ? (ruby)

Tags:

time

ruby

I have a number of seconds. Let's say 270921. How can I display that number saying it is xx days, yy hours, zz minutes, ww seconds?

like image 656
Radek Avatar asked Feb 22 '10 10:02

Radek


People also ask

How do you convert hours minutes and seconds into days?

The following code is what I use. int seconds = (totalSeconds % 60); int minutes = (totalSeconds % 3600) / 60; int hours = (totalSeconds % 86400) / 3600; int days = (totalSeconds % (86400 * 30)) / 86400; First line - We get the remainder of seconds when dividing by number of seconds in a minutes.

How do you convert SEC into time?

There are 3,600 seconds in 1 hour. The easiest way to convert seconds to hours is to divide the number of seconds by 3,600.


2 Answers

It can be done pretty concisely using divmod:

t = 270921 mm, ss = t.divmod(60)            #=> [4515, 21] hh, mm = mm.divmod(60)           #=> [75, 15] dd, hh = hh.divmod(24)           #=> [3, 3] puts "%d days, %d hours, %d minutes and %d seconds" % [dd, hh, mm, ss] #=> 3 days, 3 hours, 15 minutes and 21 seconds 

You could probably DRY it further by getting creative with collect, or maybe inject, but when the core logic is three lines it may be overkill.

like image 65
Mike Woodhouse Avatar answered Sep 18 '22 18:09

Mike Woodhouse


I was hoping there would be an easier way than using divmod, but this is the most DRY and reusable way I found to do it:

def seconds_to_units(seconds)   '%d days, %d hours, %d minutes, %d seconds' %     # the .reverse lets us put the larger units first for readability     [24,60,60].reverse.inject([seconds]) {|result, unitsize|       result[0,0] = result.shift.divmod(unitsize)       result     } end 

The method is easily adjusted by changing the format string and the first inline array (ie the [24,60,60]).

Enhanced version

class TieredUnitFormatter   # if you set this, '%d' must appear as many times as there are units   attr_accessor :format_string    def initialize(unit_names=%w(days hours minutes seconds), conversion_factors=[24, 60, 60])     @unit_names = unit_names     @factors = conversion_factors      @format_string = unit_names.map {|name| "%d #{name}" }.join(', ')     # the .reverse helps us iterate more effectively     @reversed_factors = @factors.reverse   end    # e.g. seconds   def format(smallest_unit_amount)     parts = split(smallest_unit_amount)     @format_string % parts   end    def split(smallest_unit_amount)     # go from smallest to largest unit     @reversed_factors.inject([smallest_unit_amount]) {|result, unitsize|       # Remove the most significant item (left side), convert it, then       # add the 2-element array to the left side of the result.       result[0,0] = result.shift.divmod(unitsize)       result     }   end end 

Examples:

fmt = TieredUnitFormatter.new fmt.format(270921)  # => "3 days, 3 hours, 15 minutes, 21 seconds"  fmt = TieredUnitFormatter.new(%w(minutes seconds), [60]) fmt.format(5454)  # => "90 minutes, 54 seconds" fmt.format_string = '%d:%d' fmt.format(5454)  # => "90:54" 

Note that format_string won't let you change the order of the parts (it's always the most significant value to least). For finer grained control, you can use split and manipulate the values yourself.

like image 40
Kelvin Avatar answered Sep 18 '22 18:09

Kelvin