Class: Philiprehberger::Duration
- Inherits:
-
Object
- Object
- Philiprehberger::Duration
- Includes:
- Comparable
- Defined in:
- lib/philiprehberger/duration.rb,
lib/philiprehberger/duration/parser.rb,
lib/philiprehberger/duration/version.rb,
lib/philiprehberger/duration/formatter.rb
Overview
Immutable Duration value object
Defined Under Namespace
Modules: Formatter, Parser Classes: Error
Constant Summary collapse
- VERSION =
'0.6.0'
Instance Attribute Summary collapse
-
#total_seconds ⇒ Object
readonly
Returns the value of attribute total_seconds.
Class Method Summary collapse
-
.between(time_a, time_b) ⇒ Duration
Calculate the duration between two Time objects.
-
.from_hash(weeks: 0, days: 0, hours: 0, minutes: 0, seconds: 0) ⇒ Duration
Construct a duration from named components.
-
.parse(input) ⇒ Duration
Parse a duration from a string or numeric value.
-
.parse?(input) ⇒ Duration?
Non-raising variant of ‘.parse`.
-
.zero ⇒ Duration
Return a zero-length duration.
Instance Method Summary collapse
- #*(other) ⇒ Object
- #+(other) ⇒ Object
- #-(other) ⇒ Object
- #/(other) ⇒ Object
- #<=>(other) ⇒ Object
-
#days ⇒ Integer
Extracted day component (0-6).
-
#format(pattern) ⇒ String
Format using strftime-style tokens: %W (weeks), %D (days), %H (hours, zero-padded), %M (minutes, zero-padded), %S (seconds, zero-padded), %T (H:M:S), %s (total seconds as integer), %%.
-
#hours ⇒ Integer
Extracted hour component (0-23).
-
#initialize(total_seconds) ⇒ Duration
constructor
A new instance of Duration.
- #inspect ⇒ Object
-
#minutes ⇒ Integer
Extracted minute component (0-59).
-
#round(unit) ⇒ Duration
Round to the nearest unit.
-
#seconds ⇒ Integer
Extracted second component (0-59).
- #to_days ⇒ Object
- #to_f ⇒ Object
-
#to_hash ⇒ Hash
Return components as a hash.
- #to_hours ⇒ Object
- #to_human ⇒ Object
- #to_i ⇒ Object
- #to_iso8601 ⇒ Object
- #to_minutes ⇒ Object
- #to_s ⇒ Object
- #to_seconds ⇒ Object
- #to_weeks ⇒ Object
-
#weeks ⇒ Integer
Extracted week component.
-
#zero? ⇒ Boolean
Whether this duration is zero seconds.
Constructor Details
#initialize(total_seconds) ⇒ Duration
Returns a new instance of Duration.
73 74 75 76 77 78 79 |
# File 'lib/philiprehberger/duration.rb', line 73 def initialize(total_seconds) raise Error, 'Seconds must be numeric' unless total_seconds.is_a?(Numeric) raise Error, 'Seconds must not be negative' if total_seconds.negative? @total_seconds = total_seconds.to_f freeze end |
Instance Attribute Details
#total_seconds ⇒ Object (readonly)
Returns the value of attribute total_seconds.
14 15 16 |
# File 'lib/philiprehberger/duration.rb', line 14 def total_seconds @total_seconds end |
Class Method Details
.between(time_a, time_b) ⇒ Duration
Calculate the duration between two Time objects
69 70 71 |
# File 'lib/philiprehberger/duration.rb', line 69 def self.between(time_a, time_b) new((time_b - time_a).abs) end |
.from_hash(weeks: 0, days: 0, hours: 0, minutes: 0, seconds: 0) ⇒ Duration
Construct a duration from named components
52 53 54 55 |
# File 'lib/philiprehberger/duration.rb', line 52 def self.from_hash(weeks: 0, days: 0, hours: 0, minutes: 0, seconds: 0) total = (weeks * 604_800) + (days * 86_400) + (hours * 3600) + (minutes * 60) + seconds new(total) end |
.parse(input) ⇒ Duration
Parse a duration from a string or numeric value
21 22 23 24 |
# File 'lib/philiprehberger/duration.rb', line 21 def self.parse(input) seconds = Parser.parse(input) new(seconds) end |
.parse?(input) ⇒ Duration?
Non-raising variant of ‘.parse`
Returns ‘nil` when input is `nil`, empty, or cannot be parsed. Returns a `Duration` otherwise.
rubocop:disable Style/ReturnNilInPredicateMethodDefinition
34 35 36 37 38 39 40 41 |
# File 'lib/philiprehberger/duration.rb', line 34 def self.parse?(input) return nil if input.nil? return nil if input.respond_to?(:empty?) && input.empty? parse(input) rescue Error, ArgumentError nil end |
.zero ⇒ Duration
Return a zero-length duration
60 61 62 |
# File 'lib/philiprehberger/duration.rb', line 60 def self.zero new(0) end |
Instance Method Details
#*(other) ⇒ Object
177 178 179 |
# File 'lib/philiprehberger/duration.rb', line 177 def *(other) self.class.new(@total_seconds * other) end |
#+(other) ⇒ Object
169 170 171 |
# File 'lib/philiprehberger/duration.rb', line 169 def +(other) self.class.new(@total_seconds + resolve_seconds(other)) end |
#-(other) ⇒ Object
173 174 175 |
# File 'lib/philiprehberger/duration.rb', line 173 def -(other) self.class.new(@total_seconds - resolve_seconds(other)) end |
#/(other) ⇒ Object
181 182 183 |
# File 'lib/philiprehberger/duration.rb', line 181 def /(other) self.class.new(@total_seconds / other) end |
#<=>(other) ⇒ Object
185 186 187 188 189 |
# File 'lib/philiprehberger/duration.rb', line 185 def <=>(other) return nil unless other.is_a?(Duration) @total_seconds <=> other.total_seconds end |
#days ⇒ Integer
Extracted day component (0-6)
126 127 128 |
# File 'lib/philiprehberger/duration.rb', line 126 def days (@total_seconds.to_i % 604_800) / 86_400 end |
#format(pattern) ⇒ String
Format using strftime-style tokens: %W (weeks), %D (days), %H (hours, zero-padded), %M (minutes, zero-padded), %S (seconds, zero-padded), %T (H:M:S), %s (total seconds as integer), %%
93 94 95 96 97 98 99 100 101 102 103 104 105 106 |
# File 'lib/philiprehberger/duration.rb', line 93 def format(pattern) pattern.gsub(/%[WDHMSTs%]/) do |token| case token when '%W' then weeks.to_s when '%D' then days.to_s when '%H' then hours.to_s.rjust(2, '0') when '%M' then minutes.to_s.rjust(2, '0') when '%S' then seconds.to_s.rjust(2, '0') when '%T' then "#{hours.to_s.rjust(2, '0')}:#{minutes.to_s.rjust(2, '0')}:#{seconds.to_s.rjust(2, '0')}" when '%s' then @total_seconds.to_i.to_s when '%%' then '%' end end end |
#hours ⇒ Integer
Extracted hour component (0-23)
132 133 134 |
# File 'lib/philiprehberger/duration.rb', line 132 def hours (@total_seconds.to_i % 86_400) / 3600 end |
#inspect ⇒ Object
192 |
# File 'lib/philiprehberger/duration.rb', line 192 def inspect = "#<Duration #{to_human}>" |
#minutes ⇒ Integer
Extracted minute component (0-59)
138 139 140 |
# File 'lib/philiprehberger/duration.rb', line 138 def minutes (@total_seconds.to_i % 3600) / 60 end |
#round(unit) ⇒ Duration
Round to the nearest unit
157 158 159 160 161 162 163 164 165 166 167 |
# File 'lib/philiprehberger/duration.rb', line 157 def round(unit) rounded = case unit when :week then ((@total_seconds / 604_800.0).round * 604_800) when :day then ((@total_seconds / 86_400.0).round * 86_400) when :hour then ((@total_seconds / 3600.0).round * 3600) when :minute then ((@total_seconds / 60.0).round * 60) when :second then @total_seconds.round else raise Error, "Unknown unit: #{unit}" end self.class.new(rounded) end |
#seconds ⇒ Integer
Extracted second component (0-59)
144 145 146 |
# File 'lib/philiprehberger/duration.rb', line 144 def seconds @total_seconds.to_i % 60 end |
#to_days ⇒ Object
111 |
# File 'lib/philiprehberger/duration.rb', line 111 def to_days = @total_seconds / 86_400.0 |
#to_f ⇒ Object
114 |
# File 'lib/philiprehberger/duration.rb', line 114 def to_f = @total_seconds |
#to_hash ⇒ Hash
Return components as a hash
150 151 152 |
# File 'lib/philiprehberger/duration.rb', line 150 def to_hash { weeks: weeks, days: days, hours: hours, minutes: minutes, seconds: seconds } end |
#to_hours ⇒ Object
110 |
# File 'lib/philiprehberger/duration.rb', line 110 def to_hours = @total_seconds / 3600.0 |
#to_human ⇒ Object
115 |
# File 'lib/philiprehberger/duration.rb', line 115 def to_human = Formatter.to_human(@total_seconds) |
#to_i ⇒ Object
113 |
# File 'lib/philiprehberger/duration.rb', line 113 def to_i = @total_seconds.to_i |
#to_iso8601 ⇒ Object
116 |
# File 'lib/philiprehberger/duration.rb', line 116 def to_iso8601 = Formatter.to_iso8601(@total_seconds) |
#to_minutes ⇒ Object
109 |
# File 'lib/philiprehberger/duration.rb', line 109 def to_minutes = @total_seconds / 60.0 |
#to_s ⇒ Object
191 |
# File 'lib/philiprehberger/duration.rb', line 191 def to_s = to_human |
#to_seconds ⇒ Object
108 |
# File 'lib/philiprehberger/duration.rb', line 108 def to_seconds = @total_seconds |
#to_weeks ⇒ Object
112 |
# File 'lib/philiprehberger/duration.rb', line 112 def to_weeks = @total_seconds / 604_800.0 |
#weeks ⇒ Integer
Extracted week component
120 121 122 |
# File 'lib/philiprehberger/duration.rb', line 120 def weeks @total_seconds.to_i / 604_800 end |
#zero? ⇒ Boolean
Whether this duration is zero seconds
83 84 85 |
# File 'lib/philiprehberger/duration.rb', line 83 def zero? @total_seconds.zero? end |