Immutable Duration value object with parsing, arithmetic, and formatting
gem install philiprehberger-durationImmutable Duration value object with parsing, arithmetic, and formatting
Add to your Gemfile:
gem "philiprehberger-duration"
Or install directly:
gem install philiprehberger-duration
require "philiprehberger/duration"
d = Philiprehberger::Duration.parse("2h 30m")
d.to_seconds # => 9000.0
d.to_human # => "2 hours, 30 minutes"
d.to_iso8601 # => "PT2H30M"
Duration = Philiprehberger::Duration
Duration.parse("2 weeks 3 days") # human string
Duration.parse("1 day 3 hours") # human string
Duration.parse("PT2H30M") # ISO 8601
Duration.parse("P2W") # ISO 8601 weeks
Duration.parse(3600) # numeric seconds
Use Duration.parse? for a non-raising variant that returns nil on invalid input:
Duration.parse?("2h 30m") # => Duration("2 hours, 30 minutes")
Duration.parse?("xyz") # => nil
Duration.parse?("") # => nil
Duration.parse?(nil) # => nil
d1 = Duration.parse("2h")
d2 = Duration.parse("30m")
d1 + d2 # => Duration("2 hours, 30 minutes")
d1 - d2 # => Duration("1 hour, 30 minutes")
d2 * 3 # => Duration("1 hour, 30 minutes")
d1 / 2 # => Duration("1 hour")
Duration.parse("2h") > Duration.parse("1h") # => true
Duration.parse("60m") == Duration.parse("1h") # => true
Duration.parse("2h 30m").to_short # => "2h 30m"
Duration.from_hash(weeks: 1).to_short # => "1w"
Duration.zero.to_short # => "0s"
Duration.between(start_time, end_time).to_human # => "3 hours, 15 minutes"
d = Duration.parse("2h 30m")
d.from_now # => Time.now + 9000 seconds
d.ago # => Time.now - 9000 seconds
d.since(start_time) # => start_time + 9000 seconds
d.before(deadline) # => deadline - 9000 seconds
d = Philiprehberger::Duration.parse("2 weeks 1 day 2 hours 30 minutes 45 seconds")
d.weeks # => 2
d.days # => 1
d.hours # => 2
d.minutes # => 30
d.seconds # => 45
d.to_hash # => { weeks: 2, days: 1, hours: 2, minutes: 30, seconds: 45 }
d = Philiprehberger::Duration.parse("1h 45m")
d.round(:hour).to_human # => "2 hours"
d = Philiprehberger::Duration.parse("2h 30m")
d.to_minutes # => 150.0
d.to_hours # => 2.5
d.to_days # => 0.104166...
d.to_weeks # => 0.014880...
d.to_i # => 9000
d.to_f # => 9000.0
d = Philiprehberger::Duration.from_hash(weeks: 1, days: 2, hours: 3)
d.to_human # => "1 week, 2 days, 3 hours"
d = Philiprehberger::Duration.parse("1 day 2h 3m 4s")
d.format("%D days %T") # => "1 days 02:03:04"
d.format("%H:%M:%S") # => "02:03:04"
Philiprehberger::Duration.zero.zero? # => true
| Method | Description |
|---|---|
Duration.parse(input) | Parse human string, ISO 8601, or numeric seconds |
Duration.parse?(input) | Non-raising variant of parse — returns nil on nil, empty, or invalid input |
Duration.from_hash(**components) | Construct from named components (weeks, days, hours, minutes, seconds) |
Duration.between(time_a, time_b) | Duration between two Time objects |
Duration.zero | Zero-length duration |
#zero? | Whether the duration is zero |
#format(pattern) | strftime-style formatter (%W %D %H %M %S %T %s %%) |
#to_seconds | Total seconds as float |
#to_minutes | Total minutes as float |
#to_hours | Total hours as float |
#to_days | Total days as float |
#to_weeks | Total weeks as float |
#to_i | Total seconds as integer |
#to_f | Total seconds as float |
#to_human | Human-readable string |
#to_iso8601 | ISO 8601 formatted string |
#weeks | Extracted week component |
#days | Extracted day component (0-6) |
#hours | Extracted hour component (0-23) |
#minutes | Extracted minute component (0-59) |
#seconds | Extracted second component (0-59) |
#to_hash | Components as { weeks:, days:, hours:, minutes:, seconds: } |
#from_now | Time.now + to_seconds |
#ago | Time.now - to_seconds |
#since(time) | time + to_seconds |
#before(time) | time - to_seconds |
#round(unit) | Round to nearest :week, :day, :hour, :minute, or :second |
#to_short | Compact format like "2h 30m" or "1w" |
#+, #-, #*, #/ | Arithmetic operations |
<, >, ==, <=> | Comparison (via Comparable) |
bundle install
bundle exec rspec
bundle exec rubocop
If you find this project useful: