philiprehberger-duration
Immutable Duration value object with parsing, arithmetic, and formatting
Requirements
- Ruby >= 3.1
Installation
Add to your Gemfile:
gem "philiprehberger-duration"
Or install directly:
gem install philiprehberger-duration
Usage
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"
Parsing
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
Arithmetic
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")
Comparison
Duration.parse("2h") > Duration.parse("1h") # => true
Duration.parse("60m") == Duration.parse("1h") # => true
Between Two Times
Duration.between(start_time, end_time).to_human # => "3 hours, 15 minutes"
Component Accessors
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 }
Rounding
d = Philiprehberger::Duration.parse("1h 45m")
d.round(:hour).to_human # => "2 hours"
Total Conversion
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
Constructing from Components
d = Philiprehberger::Duration.from_hash(weeks: 1, days: 2, hours: 3)
d.to_human # => "1 week, 2 days, 3 hours"
Custom Formatting
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
API
| 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: } |
#round(unit) |
Round to nearest :week, :day, :hour, :minute, or :second |
#+, #-, #*, #/ |
Arithmetic operations |
<, >, ==, <=> |
Comparison (via Comparable) |
Development
bundle install
bundle exec rspec
bundle exec rubocop
Support
If you find this project useful: