Skip to content

Instantly share code, notes, and snippets.

@chrisk
Created November 5, 2009 07:00
Show Gist options
  • Save chrisk/226836 to your computer and use it in GitHub Desktop.
Save chrisk/226836 to your computer and use it in GitHub Desktop.
DurationHelper#format_duration
module DurationHelper
# Takes a number of seconds as input and returns a formatted string. See
# tests for examples.
def format_duration(seconds, options = {})
return "0 seconds" if seconds.floor == 0
options.reverse_merge!(:parts_to_show => 4, :word_style => :short, :specific_end => false)
description = (options[:word_style] == :short) ?
[ ['sec', 60], ['min', 60], ['hr', 24], ['day'] ] :
[ ['second', 60], ['minute', 60], ['hour', 24], ['day'] ]
components = []
units = seconds.floor
description.each do |component, max|
if max
components.unshift([units % max, component])
break unless units >= max
units = units.to_f / max
else
components.unshift([units, component])
end
end
parts_shown = 0
results = components.map do |c|
next if parts_shown >= options[:parts_to_show]
parts_shown += 1
number = c.first
if options[:specific_end].present? && parts_shown == options[:parts_to_show] && c.last =~ /^(hr|hour|day)/
number = number.round_at(1).to_i_if_whole
else
number = number.floor
end
next if number == 0
"#{number} #{number == 1 ? c.last : c.last.pluralize}"
end
results.compact.join(' ')
end
end
describe DurationHelper, "#format_duration" do
it "returns the correct string for many different durations" do
helper.format_duration(212751).should == "2 days 11 hrs 5 mins 51 secs"
helper.format_duration(79805).should == "22 hrs 10 mins 5 secs"
helper.format_duration(2730).should == "45 mins 30 secs"
helper.format_duration(142800).should == "1 day 15 hrs 40 mins"
helper.format_duration(352800).should == "4 days 2 hrs"
helper.format_duration(345600).should == "4 days"
helper.format_duration(32).should == "32 secs"
helper.format_duration(32.9).should == "32 secs"
helper.format_duration(0).should == "0 seconds"
helper.format_duration(0.5).should == "0 seconds"
end
it "excludes least-significant units using the :parts_to_show option"do
helper.format_duration(212751, :parts_to_show => 1).should == "2 days"
helper.format_duration(212751, :parts_to_show => 2).should == "2 days 11 hrs"
helper.format_duration(212751, :parts_to_show => 3).should == "2 days 11 hrs 5 mins"
helper.format_duration(212751, :parts_to_show => 0).should == ""
end
it "counts a zero component that's not shown in :parts_to_show" do
# By using :parts_to_show => 3, that means we want days, hours, and minutes;
# but if hours turns out to be zero, then we'll actually just show 2 parts.
helper.format_duration(1.day + 1.minute + 1.second, :parts_to_show => 3).should == "1 day 1 min"
end
it "uses short duration words with :word_style => :short" do
helper.format_duration(2730, :word_style => :short).should == "45 mins 30 secs"
end
it "uses long duration words with :word_style => :long" do
helper.format_duration(2730, :word_style => :long).should == "45 minutes 30 seconds"
end
it "uses a float for a least-significant part in days or hours with :specific_end => true" do
helper.format_duration(352800, :specific_end => true).should == "4 days 2 hrs"
helper.format_duration(352800, :parts_to_show => 1, :specific_end => true).should == "4.1 days"
helper.format_duration(352835, :parts_to_show => 2, :specific_end => true).should == "4 days 2 hrs"
helper.format_duration(79805, :parts_to_show => 1, :specific_end => true).should == "22.2 hrs"
helper.format_duration(79805, :parts_to_show => 2, :specific_end => true).should == "22 hrs 10 mins"
helper.format_duration(79805, :parts_to_show => 3, :specific_end => true).should == "22 hrs 10 mins 5 secs"
helper.format_duration(79200, :parts_to_show => 1, :specific_end => true).should == "22 hrs"
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment