duration_in_words provides a view helper to convert ActiveSupport::Duration objects into concise string like 1h 20m and 30s, with locale support.
Currently, there is no direct way to format ActiveSupport::Duration objects in Rails. You'd have to resort to using the #inspect, which provides limited configuration options. Also, the locale support in the #inspect was removed around Rails 5.1.
You could do something like the following to format an ActiveSupport::Duration object by hand in a view helper:
def duration_as_sentence(duration)
parts = duration.parts
units = [:days, :hours, :minutes]
map = {
:days => { :one => :d },
:hours => { :one => :h, :other => :hrs },
:minutes => { :one => :m, :other => :mins }
}
parts.
sort_by { |unit, _| units.index(unit) }.
map { |unit, val| "#{val} #{val == 1 ? map[unit][:one].to_s : map[unit][:other].to_s}" }.
to_sentence
endThis gem does something similar along with providing a flexible way of defining formats in locale files and giving you an option to switch between :compact, and :full formats.
Add to your Gemfile:
gem "duration_in_words"Install the gem by running bundle install.
include ActionView::Helpers::DurationHelper
>> duration = 2.hours
>> duration_in_words(duration)
=> "2h"
>> duration = 1.day + 2.hours + 30.minutes
>> duration_in_words(duration)
=> "1d 2h and 30m"
>> duration = 2.5.minutes
>> duration_in_words(duration)
=> "2.5m"
>> duration = 3.weeks
>> duration_in_words(duration)
=> "3wks."
>> duration_in_words(duration)
=> "2.5m"There are two formats available, :compact, and :full. :compact being the default.
>> duration = 1.day + 2.hours + 30.minutes
>> duration_in_words(duration, format: :full)
=> "1 day, 2 hours, and 30 minutes"Passing anything other than :compact or :full (as a symbol or string) raises ArgumentError.
If you do not pass :locale, the helper uses the current I18n.locale.
Given this locale dictionary:
de:
duration:
in_words:
format:
compact:
years:
one: '%{count}J'
other: '%{count}J'
months:
one: '%{count}M'
other: '%{count}M'
weeks:
one: '%{count}W'
other: '%{count}W'
days:
one: '%{count}T'
other: '%{count}T'
hours:
one: '%{count}Std.'
other: '%{count}Std.'
minutes:
one: '%{count}Min'
other: '%{count}Min'
seconds:
one: '%{count}s'
other: '%{count}s'
support:
words_connector: ' '
two_words_connector: ' und '
last_word_connector: ' und '
full:
years:
one: '%{count} Jahr'
other: '%{count} Jahre'
months:
one: '%{count} Monat'
other: '%{count} Monate'
weeks:
one: '%{count} Woche'
other: '%{count} Wochen'
days:
one: '%{count} Tag'
other: '%{count} Tage'
hours:
one: '%{count} Stunde'
other: '%{count} Stunden'
minutes:
one: '%{count} Minute'
other: '%{count} Minuten'
seconds:
one: '%{count} Sekunde'
other: '%{count} Sekunden'
support:
words_connector: ', '
two_words_connector: ' und '
last_word_connector: ', und '>> duration = 1.day + 2.hours + 30.minutes
>> duration_in_words(duration, locale: :de)
=> "1T 2Std. und 30Min"
>> duration = 3.weeks
>> duration_in_words(duration, locale: :de)
=> "3W"
>> duration_in_words(duration, format: :full, locale: :de)
>> "1 Tag 2 Stunden und 30 Minuten"After checking out the repo, run bin/setup to install dependencies. Then, run rake spec to run the tests. You can also run bin/console for an interactive prompt that will allow you to experiment.
To install this gem onto your local machine, run bundle exec rake install. To release a new version, update the version number in version.rb, and then run bundle exec rake release, which will create a git tag for the version, push git commits and the created tag, and push the .gem file to rubygems.org.
Bug reports and pull requests are welcome on GitHub at https://github.com/aslam/duration_in_words.
The gem is available as open source under the terms of the MIT License.