Friday, February 26, 2010

Seconds to Days, Minutes, Hours, Seconds in Ruby

Here is how to convert a large number of seconds into days, months, hours, seconds format using Ruby (using similar in the Hourz application). total_seconds is the difference between two Ruby Time instances:
  def display_time(total_seconds)
    total_seconds = total_seconds.to_i
    
    days = total_seconds / 86400
    hours = (total_seconds / 3600) - (days * 24)
    minutes = (total_seconds / 60) - (hours * 60) - (days * 1440)
    seconds = total_seconds % 60
    
    display = ''
    display_concat = ''
    if days > 0
      display = display + display_concat + "#{days}d"
      display_concat = ' '
    end
    if hours > 0 || display.length > 0
      display = display + display_concat + "#{hours}h"
      display_concat = ' '
    end
    if minutes > 0 || display.length > 0
      display = display + display_concat + "#{minutes}m"
      display_concat = ' '
    end
    display = display + display_concat + "#{seconds}s"
    display
  end
Example in irb:
>> display_time(Time.at(12345678) - Time.at(1234567))
=> "128d 14h 25m 11s"
>> display_time(Time.at(123456789) - Time.at(12345678))
=> "1286d 0h 11m 51s"
Here is a modification that doesn't show minutes if there are days left and doesn't show seconds if there are days or hours left:
  def display_brief_time(total_seconds)
    total_seconds = total_seconds.to_i
    
    days = total_seconds / 86400
    hours = (total_seconds / 3600) - (days * 24)
    minutes = (total_seconds / 60) - (hours * 60) - (days * 1440)
    seconds = total_seconds % 60
    
    display = ''
    display_concat = ''
    if days > 0
      display = display + display_concat + "#{days}d"
      display_concat = ' '
    end
    if hours > 0 || days > 0
      display = display + display_concat + "#{hours}h"
      display_concat = ' '
    end
    if days == 0 && (minutes > 0 || hours > 0)
      display = display + display_concat + "#{minutes}m"
      display_concat = ' '
    end
    if hours == 0 && days == 0
      display = display + display_concat + "#{seconds}s"
    end
    display
  end
Example of that in irb:
>> display_brief_time(Time.at(12345678) - Time.at(1234567))
=> "128d 14h"
>> display_brief_time(Time.at(12345678) - Time.at(12345677))
=> "1s"
>> display_brief_time(Time.at(12345678) - Time.at(12345607))
=> "1m 11s"
>> display_brief_time(Time.at(12345678) - Time.at(12340607))
=> "1h 24m"
To make it even more brief, you could not show seconds unless there are less than 3 minutes left with:
def display_very_brief_time(total_seconds)
    total_seconds = total_seconds.to_i
    
    days = total_seconds / 86400
    hours = (total_seconds / 3600) - (days * 24)
    minutes = (total_seconds / 60) - (hours * 60) - (days * 1440)
    seconds = total_seconds % 60
    
    display = ''
    display_concat = ''
    if days > 0
      display = display + display_concat + "#{days}d"
      display_concat = ' '
    end
    if hours > 0 || days > 0
      display = display + display_concat + "#{hours}h"
      display_concat = ' '
    end
    if days == 0 && (minutes > 0 || hours > 0)
      display = display + display_concat + "#{minutes}m"
      display_concat = ' '
    end
    if hours == 0 && days == 0 && minutes < 3
      display = display + display_concat + "#{seconds}s"
    end
    display
  end

1 comment:

Josh P said...

Thanks man.

I wanted to use the display_time_in_words built into Rails but I needed it to be precise.

This worked great for me and saved me a bunch of time.

Cheers.

JP