A set of classes to facilitate working with and formatting durations, intervals, time ranges and occurrences.
Duranged::duration(300) # 5 minute duration
Duranged::interval(1.hour) # 1 hour interval
Duranged::range(Time.now, 30.minutes) # between now -> 30 minutes from now
Duranged::occurrence(1, 2.days) # once every 2 days
Add the gem to your project's Gemfile:
gem 'duranged'
Then run bundle install
. Or install duranged system wide with gem install duranged
.
You can configure all options using Duranged.configure
with a block wherever is appropriate for your project (for example in a rails config initializer). Below is an example along with list of all duranged config options and their defaults.
Duranged.configure do |config|
config.logger = ActiveSupport::Logger.new(STDOUT)
config.formats.date = '%b. %-d %Y'
config.formats.time = '%-l:%M%P'
end
A Duranged::Duration
or Duranged::Interval
represents a chunk of time. Their behavior is identical, and the names are mostly just aliases for different contexts and uses. The only difference is that durations respond to Duranged::Duration#duration
while intervals respond to Duranged::Interval#interval
, but both are just aliases for #value
. Most of the examples below will use a duration.
Durations and intervals can be initialized with an integer, an ActiveSupport::Duration
(i.e. 3.minutes
), a hash or a string (via the chronic_duration gem).
duration = Duranged::Duration.new(300)
#=> #<Duranged::Duration:0x007feb020f80f8 @value=300>
duration = Duranged::Duration.new(20.minutes)
#=> #<Duranged::Duration:0x007feb038534f0 @value=1200>
duration = Duranged::Duration.new({minutes: 5, seconds: 30})
#=> #<Duranged::Duration:0x007feb03838d08 @value=330>
duration = Duranged::Duration.new("1 day, 2 hours and 30 minutes")
#=> #<Duranged::Duration:0x007feb023a2650 @value=95400>
You can use the #to_s
method for default string formatting, provided by chronic_duration
.
duration = Duranged::Duration.new(1.day + 12.minutes + 2.hours + 60.minutes)
duration.to_s
#=> "1 day, 3 hours, 12 minutes"
Or the #strfdur
method for custom formatting, similiar to Time#strftime
.
duration = Duranged::Duration.new(1.day + 12.minutes + 2.hours + 32.seconds)
#=> #<Duranged::Duration:0x007faf693ab1d0 @value=94352>
# standard, zero-padded formatters
duration.strfdur('%d:%h:%m:%s')
#=> "01:02:12:32"
# prefix with _ flag for space padding
duration.strfdur('%_d:%_h:%_m:%_s')
#=> " 1: 2:12:32"
# pass a modifier to control the amount of padding
duration.strfdur('%5d:%_5h:%m:%s')
#=> "00001: 2:12:32"
# negate padding with a - flag
duration.strfdur('%-d day, %h hours, %m minutes and %s seconds')
#=> "1 day, 02 hours, 12 minutes and 32 seconds"
The #strfdur
method also accepts some custom formatters.
duration = Duranged::Duration.new(12.hours + 30.minutes)
#=> #<Duranged::Duration:0x007faf692d38c0 @value=45000>
# use :days() to only show the formatted string when the value is > 0
duration.strfdur(':days(%d days, )%h hours and %m:seconds(:%s) minutes')
#=> "12 hours and 30 minutes"
# versus without the custom formatter
duration.strfdur('%d days, %h hours and %m:%s minutes')
#=> "00 days, 12 hours and 30:00 minutes"
If you pass a custom formatter without a nested format argument, it will return the singular or plural part name.
duration = Duranged::Duration.new(2.days + 1.hours + 30.minutes)
#=> #<Duranged::Duration:0x007faf6921b388 @value=178200>
# :hours will be replaced with singular 'hour'
duration.strfdur(':days(%-d :days, )%-h :hours and %m :minutes')
#=> "2 days, 1 hour and 30 minutes"
# your case will be preserved
duration.strfdur(':days(%-d :Days, )%-h :HOURS and %m :MiNuTeS')
#=> "2 Days, 1 HOUR and 30 MiNuTeS"
TODO See the wiki for a full list of formatters.
A Duranged::Range
represents a specific chunk of time between a start and end time. Ranges can be initialized with an optional start time (defaults to now) and an end time or duration.
range = Duranged::Range.new(Time.now, 30.minutes)
#=> #<Duranged::Range:0x007faaaca86e80 @start_at=Sun, 11 Oct 2015 12:27:31 -0700, @value=1800, @end_at=Sun, 11 Oct 2015 12:57:31 -0700>
range = Duranged::Range.new(Time.now, Time.now.end_of_day)
#=> #<Duranged::Range:0x007faaadb5baf8 @start_at=Sun, 11 Oct 2015 12:28:13 -0700, @value=41506, @end_at=Sun, 11 Oct 2015 23:59:59 -0700>
range = Duranged::Range.new(Time.now.end_of_day)
#=> #<Duranged::Range:0x007faaadb3b910 @start_at=Sun, 11 Oct 2015 12:28:44 -0700, @value=41475, @end_at=Sun, 11 Oct 2015 23:59:59 -0700>
range = Duranged::Range.new(3.hours)
#=> #<Duranged::Range:0x007faaadb29fa8 @start_at=Sun, 11 Oct 2015 12:29:26 -0700, @value=10800, @end_at=Sun, 11 Oct 2015 15:29:26 -0700>
You can get string representations of ranges.
# if the range falls within the same day
range = Duranged::Range.new(Time.now, 2.hours)
#=> #<Duranged::Range:0x007faaadb112f0 @start_at=Sun, 11 Oct 2015 12:31:02 -0700, @value=7200, @end_at=Sun, 11 Oct 2015 14:31:02 -0700>
range.to_s
#=> "Oct. 11 2015 12:31pm to 2:31pm"
# if the rang spans more than one day
range = Duranged::Range.new(Time.now, Date.tomorrow.end_of_day)
#=> #<Duranged::Range:0x007faaadaea150 @start_at=Sun, 11 Oct 2015 12:32:27 -0700, @value=127652, @end_at=Mon, 12 Oct 2015 23:59:59 -0700>
range.to_s
#=> "Oct. 11 2015 12:32pm (1 day, 11 hours, 27 minutes, 32 seconds)"
And formatted strings with custom formatters.
range = Duranged::Range.new(Time.now, Date.tomorrow.end_of_day)
#=> #<Duranged::Range:0x007faaadac3f50 @start_at=Sun, 11 Oct 2015 12:34:49 -0700, @value=127510, @end_at=Mon, 12 Oct 2015 23:59:59 -0700>
# :start_at and :end_at accept standard strftime formatters, :duration accepts Duranged::Duration formatters
range.strfrange('from :start_at(%b. %-d %Y) :start_at(%-l:%M%P) to :end_at(%b. %-d %Y %-l:%M%P) (:duration(%-d:%-h:%-m:%-s))')
#=> "from Oct. 11 2015 12:34pm to Oct. 12 2015 11:59pm (1:11:25:10)"
A Duration::Occurrence
represents an event that should happen X times, optionally for Y duration, every Z interval. For example "workout once for 30 minutes every 2 days", or "water plants once every 2 days".
TODO Document occurrences
- Fork it
- Create your feature branch (
git checkout -b my-new-feature
) - Commit your changes (
git commit -am 'Add some feature'
) - Push to the branch (
git push origin my-new-feature
) - Create new Pull Request