Class: Philiprehberger::Duration
- Inherits:
-
Object
- Object
- Philiprehberger::Duration
show all
- 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.8.0'
Instance Attribute Summary collapse
Class Method Summary
collapse
Instance Method Summary
collapse
-
#*(other) ⇒ Object
-
#+(other) ⇒ Object
-
#-(other) ⇒ Object
-
#/(other) ⇒ Object
-
#<=>(other) ⇒ Object
-
#ago ⇒ Object
-
#before(time) ⇒ 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), %%.
-
#from_now ⇒ Object
-
#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).
-
#since(time) ⇒ Object
-
#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_short ⇒ 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
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 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
|
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
178
179
180
|
# File 'lib/philiprehberger/duration.rb', line 178
def *(other)
self.class.new(@total_seconds * other)
end
|
#+(other) ⇒ Object
170
171
172
|
# File 'lib/philiprehberger/duration.rb', line 170
def +(other)
self.class.new(@total_seconds + resolve_seconds(other))
end
|
#-(other) ⇒ Object
174
175
176
|
# File 'lib/philiprehberger/duration.rb', line 174
def -(other)
self.class.new(@total_seconds - resolve_seconds(other))
end
|
#/(other) ⇒ Object
182
183
184
|
# File 'lib/philiprehberger/duration.rb', line 182
def /(other)
self.class.new(@total_seconds / other)
end
|
#<=>(other) ⇒ Object
186
187
188
189
190
|
# File 'lib/philiprehberger/duration.rb', line 186
def <=>(other)
return nil unless other.is_a?(Duration)
@total_seconds <=> other.total_seconds
end
|
#ago ⇒ Object
196
197
198
|
# File 'lib/philiprehberger/duration.rb', line 196
def ago
Time.now - @total_seconds
end
|
#before(time) ⇒ Object
204
205
206
|
# File 'lib/philiprehberger/duration.rb', line 204
def before(time)
time - @total_seconds
end
|
#days ⇒ Integer
Extracted day component (0-6)
127
128
129
|
# File 'lib/philiprehberger/duration.rb', line 127
def days
(@total_seconds.to_i % 604_800) / 86_400
end
|
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
|
#from_now ⇒ Object
192
193
194
|
# File 'lib/philiprehberger/duration.rb', line 192
def from_now
Time.now + @total_seconds
end
|
#hours ⇒ Integer
Extracted hour component (0-23)
133
134
135
|
# File 'lib/philiprehberger/duration.rb', line 133
def hours
(@total_seconds.to_i % 86_400) / 3600
end
|
#inspect ⇒ Object
209
|
# File 'lib/philiprehberger/duration.rb', line 209
def inspect = "#<Duration #{to_human}>"
|
#minutes ⇒ Integer
Extracted minute component (0-59)
139
140
141
|
# File 'lib/philiprehberger/duration.rb', line 139
def minutes
(@total_seconds.to_i % 3600) / 60
end
|
Round to the nearest unit
158
159
160
161
162
163
164
165
166
167
168
|
# File 'lib/philiprehberger/duration.rb', line 158
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)
145
146
147
|
# File 'lib/philiprehberger/duration.rb', line 145
def seconds
@total_seconds.to_i % 60
end
|
#since(time) ⇒ Object
200
201
202
|
# File 'lib/philiprehberger/duration.rb', line 200
def since(time)
time + @total_seconds
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
151
152
153
|
# File 'lib/philiprehberger/duration.rb', line 151
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
208
|
# File 'lib/philiprehberger/duration.rb', line 208
def to_s = to_human
|
#to_seconds ⇒ Object
108
|
# File 'lib/philiprehberger/duration.rb', line 108
def to_seconds = @total_seconds
|
#to_short ⇒ Object
117
|
# File 'lib/philiprehberger/duration.rb', line 117
def to_short = Formatter.to_short(@total_seconds)
|
#to_weeks ⇒ Object
112
|
# File 'lib/philiprehberger/duration.rb', line 112
def to_weeks = @total_seconds / 604_800.0
|
#weeks ⇒ Integer
121
122
123
|
# File 'lib/philiprehberger/duration.rb', line 121
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
|