timerizer 0.2.1 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/timerizer.rb +70 -637
- data/lib/timerizer/core.rb +3 -0
- data/lib/timerizer/duration.rb +766 -0
- data/lib/timerizer/version.rb +3 -0
- data/lib/timerizer/wall_clock.rb +224 -0
- metadata +65 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4180c0ffb871e50a47486d122ae17fc42f37cab8
|
4
|
+
data.tar.gz: dad648d7c6fb1f996b61d5aa1c55a7c2637abc52
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 369ea12d3065905306b0649f81b6517fe49d50cd2ddd601cb7d7132571ea07b21846760bc24e75b3dee56aab841c7b42a6107f54283472e014905910ba1bbca5
|
7
|
+
data.tar.gz: 02487b58f59677d6cf481f3a3a78a6fe10f04bb598a67a445e8e1e81cb73395267526913041a53c95477882f3bd7fe95868da9a2c190bf13791775b31b4a1510
|
data/lib/timerizer.rb
CHANGED
@@ -1,621 +1,7 @@
|
|
1
|
-
require
|
1
|
+
require "date"
|
2
|
+
require_relative "./timerizer/core"
|
2
3
|
|
3
|
-
#
|
4
|
-
class RelativeTime
|
5
|
-
@@units = {
|
6
|
-
:second => :seconds,
|
7
|
-
:minute => :minutes,
|
8
|
-
:hour => :hours,
|
9
|
-
:day => :days,
|
10
|
-
:week => :weeks,
|
11
|
-
:month => :months,
|
12
|
-
:year => :years,
|
13
|
-
:decade => :decades,
|
14
|
-
:century => :centuries,
|
15
|
-
:millennium => :millennia
|
16
|
-
}
|
17
|
-
|
18
|
-
@@in_seconds = {
|
19
|
-
:second => 1,
|
20
|
-
:minute => 60,
|
21
|
-
:hour => 3600,
|
22
|
-
:day => 86400,
|
23
|
-
:week => 604800
|
24
|
-
}
|
25
|
-
|
26
|
-
@@in_months = {
|
27
|
-
:month => 1,
|
28
|
-
:year => 12,
|
29
|
-
:decade => 120,
|
30
|
-
:century => 1200,
|
31
|
-
:millennium => 12000
|
32
|
-
}
|
33
|
-
|
34
|
-
# Average amount of time in a given unit. Used internally within the {#average} and {#unaverage} methods.
|
35
|
-
@@average_seconds = {
|
36
|
-
:month => 2629746,
|
37
|
-
:year => 31556952
|
38
|
-
}
|
39
|
-
|
40
|
-
# Default syntax formats that can be used with #to_s
|
41
|
-
# @see #to_s
|
42
|
-
@@syntaxes = {
|
43
|
-
:micro => {
|
44
|
-
:units => {
|
45
|
-
:seconds => 's',
|
46
|
-
:minutes => 'm',
|
47
|
-
:hours => 'h',
|
48
|
-
:days => 'd',
|
49
|
-
:weeks => 'w',
|
50
|
-
:months => 'mn',
|
51
|
-
:years => 'y',
|
52
|
-
},
|
53
|
-
:separator => '',
|
54
|
-
:delimiter => ' ',
|
55
|
-
:count => 1
|
56
|
-
},
|
57
|
-
:short => {
|
58
|
-
:units => {
|
59
|
-
:seconds => 'sec',
|
60
|
-
:minutes => 'min',
|
61
|
-
:hours => 'hr',
|
62
|
-
:days => 'd',
|
63
|
-
:weeks => 'wk',
|
64
|
-
:months => 'mn',
|
65
|
-
:years => 'yr',
|
66
|
-
:centuries => 'ct',
|
67
|
-
:millenia => 'ml'
|
68
|
-
},
|
69
|
-
:separator => '',
|
70
|
-
:delimiter => ' ',
|
71
|
-
:count => 2
|
72
|
-
},
|
73
|
-
:long => {
|
74
|
-
:units => {
|
75
|
-
:seconds => ['second', 'seconds'],
|
76
|
-
:minutes => ['minute', 'minutes'],
|
77
|
-
:hours => ['hour', 'hours'],
|
78
|
-
:days => ['day', 'days'],
|
79
|
-
:weeks => ['week', 'weeks'],
|
80
|
-
:months => ['month', 'months'],
|
81
|
-
:years => ['year', 'years'],
|
82
|
-
:centuries => ['century', 'centuries'],
|
83
|
-
:millennia => ['millenium', 'millenia'],
|
84
|
-
}
|
85
|
-
}
|
86
|
-
}
|
87
|
-
|
88
|
-
# All potential units. Key is the unit name, and the value is its plural form.
|
89
|
-
def self.units
|
90
|
-
@@units
|
91
|
-
end
|
92
|
-
|
93
|
-
# Unit values in seconds. If a unit is not present in this hash, it is assumed to be in the {@@in_months} hash.
|
94
|
-
def self.units_in_seconds
|
95
|
-
@@in_seconds
|
96
|
-
end
|
97
|
-
|
98
|
-
# Unit values in months. If a unit is not present in this hash, it is assumed to be in the {@@in_seconds} hash.
|
99
|
-
def self.units_in_months
|
100
|
-
@@in_months
|
101
|
-
end
|
102
|
-
|
103
|
-
# Initialize a new instance of RelativeTime.
|
104
|
-
# @overload new(hash)
|
105
|
-
# @param [Hash] units The base units to initialize with
|
106
|
-
# @option units [Integer] :seconds The number of seconds
|
107
|
-
# @option units [Integer] :months The number of months
|
108
|
-
# @overload new(count, unit)
|
109
|
-
# @param [Integer] count The number of units to initialize with
|
110
|
-
# @param [Symbol] unit The unit to initialize. See {RelativeTime#units}
|
111
|
-
def initialize(count = 0, unit = :second)
|
112
|
-
if count.is_a? Hash
|
113
|
-
units = count
|
114
|
-
units.default = 0
|
115
|
-
@seconds, @months = units.values_at(:seconds, :months)
|
116
|
-
else
|
117
|
-
@seconds = @months = 0
|
118
|
-
|
119
|
-
if @@in_seconds.has_key?(unit)
|
120
|
-
@seconds = count * @@in_seconds.fetch(unit)
|
121
|
-
elsif @@in_months.has_key?(unit)
|
122
|
-
@months = count * @@in_months.fetch(unit)
|
123
|
-
end
|
124
|
-
end
|
125
|
-
end
|
126
|
-
|
127
|
-
# Compares two RelativeTimes to determine if they are equal
|
128
|
-
# @param [RelativeTime] time The RelativeTime to compare
|
129
|
-
# @return [Boolean] True if both RelativeTimes are equal
|
130
|
-
# @note Be weary of rounding; this method compares both RelativeTimes' base units
|
131
|
-
def ==(time)
|
132
|
-
if time.is_a?(RelativeTime)
|
133
|
-
@seconds == time.get(:seconds) && @months == time.get(:months)
|
134
|
-
else
|
135
|
-
false
|
136
|
-
end
|
137
|
-
end
|
138
|
-
|
139
|
-
# Return the number of base units in a RelativeTime.
|
140
|
-
# @param [Symbol] unit The unit to return, either :seconds or :months
|
141
|
-
# @return [Integer] The requested unit count
|
142
|
-
# @raise [ArgumentError] Unit requested was not :seconds or :months
|
143
|
-
def get(unit)
|
144
|
-
if unit == :seconds
|
145
|
-
@seconds
|
146
|
-
elsif unit == :months
|
147
|
-
@months
|
148
|
-
else
|
149
|
-
raise ArgumentError
|
150
|
-
end
|
151
|
-
end
|
152
|
-
|
153
|
-
# Determines the time between RelativeTime and the given time.
|
154
|
-
# @param [Time] time The initial time.
|
155
|
-
# @return [Time] The difference between the current RelativeTime and the given time
|
156
|
-
# @example 5 hours before January 1st, 2000 at noon
|
157
|
-
# 5.minutes.before(Time.new(2000, 1, 1, 12, 00, 00))
|
158
|
-
# => 2000-01-01 11:55:00 -0800
|
159
|
-
# @see #ago
|
160
|
-
# @see #after
|
161
|
-
# @see #from_now
|
162
|
-
def before(time)
|
163
|
-
time = time.to_time - @seconds
|
164
|
-
|
165
|
-
new_month = time.month - self.months
|
166
|
-
new_year = time.year - self.years
|
167
|
-
while new_month < 1
|
168
|
-
new_month += 12
|
169
|
-
new_year -= 1
|
170
|
-
end
|
171
|
-
if Date.valid_date?(new_year, new_month, time.day)
|
172
|
-
new_day = time.day
|
173
|
-
else
|
174
|
-
new_day = Date.new(new_year, new_month).days_in_month
|
175
|
-
end
|
176
|
-
|
177
|
-
new_time = Time.new(
|
178
|
-
new_year, new_month, new_day,
|
179
|
-
time.hour, time.min, time.sec
|
180
|
-
)
|
181
|
-
Time.at(new_time.to_i, time.nsec/1000)
|
182
|
-
end
|
183
|
-
|
184
|
-
# Return the time between the RelativeTime and the current time.
|
185
|
-
# @return [Time] The difference between the current RelativeTime and Time#now
|
186
|
-
# @see #before
|
187
|
-
def ago
|
188
|
-
self.before(Time.now)
|
189
|
-
end
|
190
|
-
|
191
|
-
# Return the time after the given time according to the current RelativeTime.
|
192
|
-
# @param [Time] time The starting time
|
193
|
-
# @return [Time] The time after the current RelativeTime and the given time
|
194
|
-
# @see #before
|
195
|
-
def after(time)
|
196
|
-
time = time.to_time + @seconds
|
197
|
-
|
198
|
-
new_year = time.year + self.years
|
199
|
-
new_month = time.month + self.months
|
200
|
-
while new_month > 12
|
201
|
-
new_year += 1
|
202
|
-
new_month -= 12
|
203
|
-
end
|
204
|
-
if Date.valid_date?(new_year, new_month, time.day)
|
205
|
-
new_day = time.day
|
206
|
-
else
|
207
|
-
new_day = Date.new(new_year, new_month).days_in_month
|
208
|
-
end
|
209
|
-
|
210
|
-
|
211
|
-
new_time = Time.new(
|
212
|
-
new_year, new_month, new_day,
|
213
|
-
time.hour, time.min, time.sec
|
214
|
-
)
|
215
|
-
Time.at(new_time.to_i, time.nsec/1000.0)
|
216
|
-
end
|
217
|
-
|
218
|
-
# Return the time after the current time and the RelativeTime.
|
219
|
-
# @return [Time] The time after the current time
|
220
|
-
def from_now
|
221
|
-
self.after(Time.now)
|
222
|
-
end
|
223
|
-
|
224
|
-
@@units.each do |unit, plural|
|
225
|
-
in_method = "in_#{plural}"
|
226
|
-
count_method = plural
|
227
|
-
superior_unit = @@units.keys.index(unit) + 1
|
228
|
-
|
229
|
-
if @@in_seconds.has_key? unit
|
230
|
-
class_eval "
|
231
|
-
def #{in_method}
|
232
|
-
@seconds / #{@@in_seconds[unit]}
|
233
|
-
end
|
234
|
-
"
|
235
|
-
elsif @@in_months.has_key? unit
|
236
|
-
class_eval "
|
237
|
-
def #{in_method}
|
238
|
-
@months / #{@@in_months[unit]}
|
239
|
-
end
|
240
|
-
"
|
241
|
-
end
|
242
|
-
|
243
|
-
in_superior = "in_#{@@units.values[superior_unit]}"
|
244
|
-
count_superior = @@units.keys[superior_unit]
|
245
|
-
|
246
|
-
|
247
|
-
class_eval "
|
248
|
-
def #{count_method}
|
249
|
-
time = self.#{in_method}
|
250
|
-
if @@units.length > #{superior_unit}
|
251
|
-
time -= self.#{in_superior}.#{count_superior}.#{in_method}
|
252
|
-
end
|
253
|
-
time
|
254
|
-
end
|
255
|
-
"
|
256
|
-
end
|
257
|
-
|
258
|
-
# Average second-based units to month-based units.
|
259
|
-
# @return [RelativeTime] The averaged RelativeTime
|
260
|
-
# @example
|
261
|
-
# 5.weeks.average
|
262
|
-
# => 1 month, 4 days, 13 hours, 30 minutes, 54 seconds
|
263
|
-
# @see #average!
|
264
|
-
# @see #unaverage
|
265
|
-
def average
|
266
|
-
if @seconds > 0
|
267
|
-
months = (@seconds / @@average_seconds[:month])
|
268
|
-
seconds = @seconds - months.months.unaverage.get(:seconds)
|
269
|
-
RelativeTime.new(
|
270
|
-
:seconds => seconds,
|
271
|
-
:months => months + @months
|
272
|
-
)
|
273
|
-
else
|
274
|
-
self
|
275
|
-
end
|
276
|
-
end
|
277
|
-
|
278
|
-
# Destructively average second-based units to month-based units.
|
279
|
-
# @see #average
|
280
|
-
def average!
|
281
|
-
averaged = self.average
|
282
|
-
@seconds = averaged.get(:seconds)
|
283
|
-
@months = averaged.get(:months)
|
284
|
-
self
|
285
|
-
end
|
286
|
-
|
287
|
-
# Average month-based units to second-based units.
|
288
|
-
# @return [RelativeTime] the unaveraged RelativeTime.
|
289
|
-
# @example
|
290
|
-
# 1.month.unaverage
|
291
|
-
# => 4 weeks, 2 days, 10 hours, 29 minutes, 6 seconds
|
292
|
-
# @see #average
|
293
|
-
# @see #unaverage!
|
294
|
-
def unaverage
|
295
|
-
seconds = @@average_seconds[:month] * @months
|
296
|
-
seconds += @seconds
|
297
|
-
RelativeTime.new(:seconds => seconds)
|
298
|
-
end
|
299
|
-
|
300
|
-
# Destructively average month-based units to second-based units.
|
301
|
-
# @see #unaverage
|
302
|
-
def unaverage!
|
303
|
-
unaveraged = self.average
|
304
|
-
@seconds = unaverage.get(:seconds)
|
305
|
-
@months = unaverage.get(:months)
|
306
|
-
self
|
307
|
-
end
|
308
|
-
|
309
|
-
# Add two {RelativeTime}s together.
|
310
|
-
# @raise ArgumentError Argument isn't a {RelativeTime}
|
311
|
-
# @see #-
|
312
|
-
def +(time)
|
313
|
-
raise ArgumentError unless time.is_a?(RelativeTime)
|
314
|
-
RelativeTime.new({
|
315
|
-
:seconds => @seconds + time.get(:seconds),
|
316
|
-
:months => @months + time.get(:months)
|
317
|
-
})
|
318
|
-
end
|
319
|
-
|
320
|
-
# Find the difference between two {RelativeTime}s.
|
321
|
-
# @raise ArgumentError Argument isn't a {RelativeTime}
|
322
|
-
# @see #+
|
323
|
-
def -(time)
|
324
|
-
raise ArgumentError unless time.is_a?(RelativeTime)
|
325
|
-
RelativeTime.new({
|
326
|
-
:seconds => @seconds - time.get(:seconds),
|
327
|
-
:months => @months - time.get(:months)
|
328
|
-
})
|
329
|
-
end
|
330
|
-
|
331
|
-
# Converts {RelativeTime} to {WallClock}
|
332
|
-
# @return [WallClock] {RelativeTime} as {WallClock}
|
333
|
-
# @example
|
334
|
-
# (17.hours 30.minutes).to_wall
|
335
|
-
# # => 5:30:00 PM
|
336
|
-
def to_wall
|
337
|
-
raise WallClock::TimeOutOfBoundsError if @months > 0
|
338
|
-
WallClock.new(:second => @seconds)
|
339
|
-
end
|
340
|
-
|
341
|
-
# Convert {RelativeTime} to a human-readable format.
|
342
|
-
# @overload to_s(syntax)
|
343
|
-
# @param [Symbol] syntax The syntax from @@syntaxes to use
|
344
|
-
# @overload to_s(hash)
|
345
|
-
# @param [Hash] hash The custom hash to use
|
346
|
-
# @option hash [Hash] :units The unit names to use. See @@syntaxes for examples
|
347
|
-
# @option hash [Integer] :count The maximum number of units to output. `1` would output only the unit of greatest example (such as the hour value in `1.hour 3.minutes 2.seconds`).
|
348
|
-
# @option hash [String] :separator The separator to use in between a unit and its value
|
349
|
-
# @option hash [String] :delimiter The delimiter to use in between different unit-value pairs
|
350
|
-
# @example
|
351
|
-
# (14.months 49.hours).to_s
|
352
|
-
# => 2 years, 2 months, 3 days, 1 hour
|
353
|
-
# (1.day 3.hours 4.minutes).to_s(:short)
|
354
|
-
# => 1d 3hr
|
355
|
-
# @raise KeyError Symbol argument isn't in @@syntaxes
|
356
|
-
# @raise ArgumentError Argument isn't a hash (if not a symbol)
|
357
|
-
# @see @@syntaxes
|
358
|
-
def to_s(syntax = :long)
|
359
|
-
if syntax.is_a? Symbol
|
360
|
-
syntax = @@syntaxes.fetch(syntax)
|
361
|
-
end
|
362
|
-
|
363
|
-
raise ArgumentError unless syntax.is_a? Hash
|
364
|
-
times = []
|
365
|
-
|
366
|
-
if syntax[:count].nil? || syntax[:count] == :all
|
367
|
-
syntax[:count] = @@units.count
|
368
|
-
end
|
369
|
-
units = syntax.fetch(:units)
|
370
|
-
|
371
|
-
count = 0
|
372
|
-
units = Hash[units.to_a.reverse]
|
373
|
-
units.each do |unit, (singular, plural)|
|
374
|
-
if count < syntax.fetch(:count)
|
375
|
-
time = self.respond_to?(unit) ? self.send(unit) : 0
|
376
|
-
|
377
|
-
if time > 1 && !plural.nil?
|
378
|
-
times << [time, plural]
|
379
|
-
count += 1
|
380
|
-
elsif time > 0
|
381
|
-
times << [time, singular]
|
382
|
-
count += 1
|
383
|
-
end
|
384
|
-
end
|
385
|
-
end
|
386
|
-
|
387
|
-
times.map do |time|
|
388
|
-
time.join(syntax[:separator] || ' ')
|
389
|
-
end.join(syntax[:delimiter] || ', ')
|
390
|
-
end
|
391
|
-
end
|
392
|
-
|
393
|
-
# Represents a time, but not a date. '`7:00 PM`' would be an example of a WallClock object
|
394
|
-
class WallClock
|
395
|
-
# Represents an error where an invalid meridiem was passed to WallClock.
|
396
|
-
# @see #new
|
397
|
-
class InvalidMeridiemError < ArgumentError; end
|
398
|
-
# Represents an error where a time beyond 24 hours was passed to WallClock.
|
399
|
-
# @see #new
|
400
|
-
class TimeOutOfBoundsError < ArgumentError; end
|
401
|
-
|
402
|
-
# Initialize a new instance of WallClock
|
403
|
-
# @overload new(hash)
|
404
|
-
# @param [Hash] units The units to initialize with
|
405
|
-
# @option units [Integer] :hour The hour to initialize with
|
406
|
-
# @option units [Integer] :minute The minute to initialize with
|
407
|
-
# @option units [Integer] :second The second to initialize with
|
408
|
-
# @overload new(hour, minute, meridiem)
|
409
|
-
# @param [Integer] hour The hour to initialize with
|
410
|
-
# @param [Integer] minute The minute to initialize with
|
411
|
-
# @param [Symbol] meridiem The meridiem to initialize with (`:am` or `:pm`)
|
412
|
-
# @overload new(hour, minute, second, meridiem)
|
413
|
-
# @param [Integer] hour The hour to initialize with
|
414
|
-
# @param [Integer] minute The minute to initialize with
|
415
|
-
# @param [Integer] second The second to initialize with
|
416
|
-
# @param [Symbol] meridiem The meridiem to initialize with (`:am` or `:pm`)
|
417
|
-
# @overload new(seconds)
|
418
|
-
# @param [Integer] seconds The number of seconds to initialize with (for use with #to_i)
|
419
|
-
# @raise InvalidMeridiemError Meridiem is not `:am` or `:pm`
|
420
|
-
def initialize(hour = nil, minute = nil, second = 0, meridiem = :am)
|
421
|
-
units = nil
|
422
|
-
if hour.is_a?(Integer) && minute.nil?
|
423
|
-
units = {:second => hour}
|
424
|
-
elsif hour.is_a?(Hash)
|
425
|
-
units = hour
|
426
|
-
end
|
427
|
-
|
428
|
-
if !units.nil?
|
429
|
-
second = units[:second] || 0
|
430
|
-
minute = units[:minute] || 0
|
431
|
-
hour = units[:hour] || 0
|
432
|
-
else
|
433
|
-
if second.is_a?(String) || second.is_a?(Symbol)
|
434
|
-
meridiem = second
|
435
|
-
second = 0
|
436
|
-
end
|
437
|
-
|
438
|
-
meridiem = meridiem.downcase.to_sym
|
439
|
-
if !(meridiem == :am || meridiem == :pm)
|
440
|
-
raise InvalidMeridiemError
|
441
|
-
elsif meridiem == :pm && hour > 12
|
442
|
-
raise TimeOutOfBoundsError, "hour must be <= 12 for PM"
|
443
|
-
elsif hour >= 24 || minute >= 60 || second >= 60
|
444
|
-
raise TimeOutOfBoundsError
|
445
|
-
end
|
446
|
-
|
447
|
-
hour += 12 if (meridiem == :pm and !(hour == 12))
|
448
|
-
end
|
449
|
-
|
450
|
-
@seconds =
|
451
|
-
RelativeTime.units_in_seconds.fetch(:hour) * hour +
|
452
|
-
RelativeTime.units_in_seconds.fetch(:minute) * minute +
|
453
|
-
second
|
454
|
-
|
455
|
-
if @seconds >= RelativeTime.units_in_seconds.fetch(:day)
|
456
|
-
raise TimeOutOfBoundsError
|
457
|
-
end
|
458
|
-
end
|
459
|
-
|
460
|
-
# Takes a string and turns it into a WallClock time
|
461
|
-
# @param [String] string The string to convert
|
462
|
-
# @return [WallClock] The time as a WallClock
|
463
|
-
# @example
|
464
|
-
# WallClock.from_string("10:30 PM")
|
465
|
-
# # => 10:30:00 PM
|
466
|
-
# WallClock.from_string("13:01:23")
|
467
|
-
# # => 1:01:23 PM
|
468
|
-
# @see #to_s
|
469
|
-
def self.from_string(string)
|
470
|
-
time, meridiem = string.split(' ', 2)
|
471
|
-
hour, minute, second = time.split(':', 3)
|
472
|
-
WallClock.new(hour.to_i, minute.to_i, second.to_i || 0, meridiem || :am)
|
473
|
-
end
|
474
|
-
|
475
|
-
# Returns the time of the WallClock on a date
|
476
|
-
# @param [Date] date The date to apply the time on
|
477
|
-
# @return [Time] The time after the given date
|
478
|
-
# @example yesterday at 5:00
|
479
|
-
# time = WallClock.new(5, 00, :pm)
|
480
|
-
# time.on(Date.yesterday)
|
481
|
-
# => 2000-1-1 17:00:00 -0800
|
482
|
-
def on(date)
|
483
|
-
date.to_date.to_time + @seconds
|
484
|
-
end
|
485
|
-
|
486
|
-
# Comparse two {WallClock}s.
|
487
|
-
# @return [Boolean] True if the WallClocks are identical
|
488
|
-
def ==(time)
|
489
|
-
if time.is_a? WallClock
|
490
|
-
self.in_seconds == time.in_seconds
|
491
|
-
else
|
492
|
-
false
|
493
|
-
end
|
494
|
-
end
|
495
|
-
|
496
|
-
# Get the time of the WallClock, in seconds
|
497
|
-
# @return [Integer] The total time of the WallClock, in seconds
|
498
|
-
def in_seconds
|
499
|
-
@seconds
|
500
|
-
end
|
501
|
-
|
502
|
-
# Get the time of the WallClock, in minutes
|
503
|
-
# @return [Integer] The total time of the WallClock, in minutes
|
504
|
-
def in_minutes
|
505
|
-
@seconds / RelativeTime.units_in_seconds[:minute]
|
506
|
-
end
|
507
|
-
|
508
|
-
# Get the time of the WallClock, in hours
|
509
|
-
# @return [Integer] The total time of the WallClock, in hours
|
510
|
-
def in_hours
|
511
|
-
@seconds / RelativeTime.units_in_seconds[:hour]
|
512
|
-
end
|
513
|
-
|
514
|
-
# Get the second of the WallClock.
|
515
|
-
# @return [Integer] The second component of the WallClock
|
516
|
-
def second
|
517
|
-
self.to_relative.seconds
|
518
|
-
end
|
519
|
-
|
520
|
-
# Get the minute of the WallClock.
|
521
|
-
# @return [Integer] The minute component of the WallClock
|
522
|
-
def minute
|
523
|
-
self.to_relative.minutes
|
524
|
-
end
|
525
|
-
|
526
|
-
# Get the hour of the WallClock.
|
527
|
-
# @param [Symbol] system The houring system to use (either `:twelve_hour` or `:twenty_four_hour`; default `:twenty_four_hour`)
|
528
|
-
# @return [Integer] The hour component of the WallClock
|
529
|
-
def hour(system = :twenty_four_hour)
|
530
|
-
hour = self.to_relative.hours
|
531
|
-
if system == :twelve_hour
|
532
|
-
if hour == 0
|
533
|
-
12
|
534
|
-
elsif hour > 12
|
535
|
-
hour - 12
|
536
|
-
else
|
537
|
-
hour
|
538
|
-
end
|
539
|
-
elsif (system == :twenty_four_hour)
|
540
|
-
hour
|
541
|
-
else
|
542
|
-
raise ArgumentError, "system should be :twelve_hour or :twenty_four_hour"
|
543
|
-
end
|
544
|
-
end
|
545
|
-
|
546
|
-
# Get the meridiem of the WallClock.
|
547
|
-
# @return [Symbol] The meridiem (either `:am` or `:pm`)
|
548
|
-
def meridiem
|
549
|
-
if self.hour > 12 || self.hour == 0
|
550
|
-
:pm
|
551
|
-
else
|
552
|
-
:am
|
553
|
-
end
|
554
|
-
end
|
555
|
-
|
556
|
-
# Converts self to {WallClock}
|
557
|
-
# @see Time#to_wall
|
558
|
-
def to_wall
|
559
|
-
self
|
560
|
-
end
|
561
|
-
|
562
|
-
# Converts {WallClock} to {RelativeTime}
|
563
|
-
# @return [RelativeTime] {WallClock} as {RelativeTime}
|
564
|
-
# @example
|
565
|
-
# time = WallClock.new(5, 30, :pm)
|
566
|
-
# time.to_relative
|
567
|
-
# => 5 hours, 30 minutes
|
568
|
-
def to_relative
|
569
|
-
@seconds.seconds
|
570
|
-
end
|
571
|
-
|
572
|
-
# Get the time of the WallClock in a more portable format (for a database, for example)
|
573
|
-
# @see #in_seconds
|
574
|
-
def to_i
|
575
|
-
self.in_seconds
|
576
|
-
end
|
577
|
-
|
578
|
-
# Convert {WallClock} to a human-readable format.
|
579
|
-
# @param [Symbol] system The hour system to use (`:twelve_hour` or `:twenty_four_hour`; default `:twelve_hour`)
|
580
|
-
# @param [Hash] options Extra options for the string to use
|
581
|
-
# @option options [Boolean] :use_seconds Whether or not to include seconds in the conversion to a string
|
582
|
-
# @option options [Boolean] :include_meridian Whether or not to include the meridian for a twelve-hour time
|
583
|
-
# @example
|
584
|
-
# time = WallClock.new(5, 37, 41, :pm)
|
585
|
-
# time.to_s
|
586
|
-
# => "5:37:41 PM"
|
587
|
-
# time.to_s(:twenty_four_hour, :use_seconds => true)
|
588
|
-
# => "17:37:41"
|
589
|
-
# time.to_s(:twelve_hour, :use_seconds => false, :include_meridiem => false)
|
590
|
-
# => "5:37"
|
591
|
-
# time.to_s(:twenty_four_hour, :use_seconds =>false)
|
592
|
-
# => "17:37"
|
593
|
-
# @raise ArgumentError Argument isn't a proper system
|
594
|
-
def to_s(system = :twelve_hour, options = {})
|
595
|
-
options = {:use_seconds => true, :include_meridiem => true}.merge(options)
|
596
|
-
pad = "%02d"
|
597
|
-
meridiem = self.meridiem.to_s.upcase
|
598
|
-
hour = self.hour(system)
|
599
|
-
minute = pad % self.minute
|
600
|
-
second = pad % self.second
|
601
|
-
|
602
|
-
string = [hour, minute].join(':')
|
603
|
-
if options[:use_seconds]
|
604
|
-
string = [string, second].join(':')
|
605
|
-
end
|
606
|
-
|
607
|
-
case system
|
608
|
-
when :twelve_hour
|
609
|
-
options[:include_meridiem] ? [string, meridiem].join(' ') : string
|
610
|
-
when :twenty_four_hour
|
611
|
-
string
|
612
|
-
else
|
613
|
-
raise ArgumentError, "system should be :twelve_hour or :twenty_four_hour"
|
614
|
-
end
|
615
|
-
end
|
616
|
-
end
|
617
|
-
|
618
|
-
# {Time} class monkeywrenched with {RelativeTime} support.
|
4
|
+
# {Time} class monkey-patched with {Timerizer::Duration} support.
|
619
5
|
class Time
|
620
6
|
# Represents an error where two times were expected to be in the future, but were in the past.
|
621
7
|
# @see #until
|
@@ -650,7 +36,7 @@ class Time
|
|
650
36
|
|
651
37
|
alias_method :add, :+
|
652
38
|
def +(time)
|
653
|
-
if time.is_a?
|
39
|
+
if time.is_a?(Timerizer::Duration)
|
654
40
|
time.after(self)
|
655
41
|
else
|
656
42
|
self.add(time)
|
@@ -659,7 +45,7 @@ class Time
|
|
659
45
|
|
660
46
|
alias_method :subtract, :-
|
661
47
|
def -(time)
|
662
|
-
if time.is_a?
|
48
|
+
if time.is_a?(Timerizer::Duration)
|
663
49
|
time.before(self)
|
664
50
|
else
|
665
51
|
self.subtract(time)
|
@@ -668,7 +54,7 @@ class Time
|
|
668
54
|
|
669
55
|
# Calculates the time until a given time
|
670
56
|
# @param [Time] time The time until now to calculate
|
671
|
-
# @return [
|
57
|
+
# @return [Duration] The time until the provided time
|
672
58
|
# @raise[TimeIsInThePastException] The provided time is in the past
|
673
59
|
# @example
|
674
60
|
# Time.until(Time.new(2012, 12, 25))
|
@@ -683,7 +69,7 @@ class Time
|
|
683
69
|
|
684
70
|
# Calculates the time since a given time
|
685
71
|
# @param [Time] time The time to calculate since now
|
686
|
-
# @return [
|
72
|
+
# @return [Duration] The time since the provided time
|
687
73
|
# @raise[TimeIsInTheFutureException] The provided time is in the future
|
688
74
|
# @example
|
689
75
|
# Time.since(Time.new(2011, 10, 31))
|
@@ -699,7 +85,7 @@ class Time
|
|
699
85
|
# Calculate the amount of time between two times.
|
700
86
|
# @param [Time] time1 The initial time
|
701
87
|
# @param [Time] time2 The final time
|
702
|
-
# @return [
|
88
|
+
# @return [Duration] Calculated time between time1 and time2
|
703
89
|
# @example
|
704
90
|
# Time.between(1.minute.ago, 1.hour.ago)
|
705
91
|
# => 59.minutes
|
@@ -709,7 +95,7 @@ class Time
|
|
709
95
|
def self.between(time1, time2)
|
710
96
|
time_between = (time2.to_time - time1.to_time).abs
|
711
97
|
|
712
|
-
|
98
|
+
Timerizer::Duration.new(seconds: time_between.round)
|
713
99
|
end
|
714
100
|
|
715
101
|
# Convert {Time} to {Date}.
|
@@ -727,19 +113,19 @@ class Time
|
|
727
113
|
self
|
728
114
|
end
|
729
115
|
|
730
|
-
# Converts {Time} to {WallClock}
|
731
|
-
# @return [WallClock] {Time} as {WallClock}
|
116
|
+
# Converts {Time} to {Timerizer::WallClock}
|
117
|
+
# @return [Timerizer::WallClock] {Time} as {Timerizer::WallClock}
|
732
118
|
# @example
|
733
119
|
# time = Time.now.to_wall
|
734
120
|
# Date.tomorrow.at(time)
|
735
121
|
# => 2000-1-2 13:13:27 -0800
|
736
122
|
# # "Same time tomorrow?"
|
737
123
|
def to_wall
|
738
|
-
WallClock.new(self.hour, self.min, self.sec)
|
124
|
+
Timerizer::WallClock.new(self.hour, self.min, self.sec)
|
739
125
|
end
|
740
126
|
end
|
741
127
|
|
742
|
-
# {Date} class
|
128
|
+
# {Date} class monkey-patched with {Timerizer::Duration} helpers.
|
743
129
|
class Date
|
744
130
|
# Return the number of days in a given month.
|
745
131
|
# @return [Integer] Number of days in the month of the {Date}.
|
@@ -783,19 +169,66 @@ class Date
|
|
783
169
|
end
|
784
170
|
end
|
785
171
|
|
786
|
-
#
|
172
|
+
# Monkey-patched {Integer} class enabled to return {Timerizer::Duration}s.
|
787
173
|
# @example
|
788
174
|
# 5.minutes
|
789
|
-
#
|
790
|
-
# @see
|
175
|
+
# # => 5 minutes
|
176
|
+
# @see Timerizer::Duration::UNITS
|
791
177
|
class Integer
|
792
|
-
|
793
|
-
|
794
|
-
|
795
|
-
|
796
|
-
|
178
|
+
private
|
179
|
+
|
180
|
+
# @!macro [attach] _define_duration_unit
|
181
|
+
# @method $1(other = nil)
|
182
|
+
#
|
183
|
+
# Return a {Timerizer::Duration} with `self` of the given unit. This
|
184
|
+
# method is a helper that is equivalent to
|
185
|
+
# `Timerizer::Duration::new($1: self)`.
|
186
|
+
#
|
187
|
+
# @param [Timerizer::Duration, nil] other Another duration to add to the
|
188
|
+
# resulting duration, if present. This argument allows "chaining" multiple
|
189
|
+
# durations together, to combine multiple units succiently.
|
190
|
+
#
|
191
|
+
# @return [Timerizer::Duration] the quantity of the unit in the duration.
|
192
|
+
#
|
193
|
+
# @see Timerizer::Duration#initialize
|
194
|
+
#
|
195
|
+
# @example
|
196
|
+
# n.$1 == Timerizer::Duration.new($1: n)
|
197
|
+
# 5.minutes == Timerizer::Duration.new(minutes: 5)
|
198
|
+
# (1.week 1.day) == 8.days # "Chaining" multiple units
|
199
|
+
# (n.$1 x.minutes) == (n.$1 + x.minutes)
|
200
|
+
def self._define_duration_unit(unit)
|
201
|
+
define_method(unit) do |other = nil|
|
202
|
+
duration = Timerizer::Duration.new(unit => self)
|
203
|
+
|
204
|
+
if other.nil?
|
205
|
+
duration
|
206
|
+
else
|
207
|
+
duration + other
|
797
208
|
end
|
798
|
-
|
799
|
-
alias_method(plural, unit)
|
209
|
+
end
|
800
210
|
end
|
211
|
+
|
212
|
+
public
|
213
|
+
|
214
|
+
self._define_duration_unit(:seconds)
|
215
|
+
self._define_duration_unit(:minutes)
|
216
|
+
self._define_duration_unit(:hours)
|
217
|
+
self._define_duration_unit(:days)
|
218
|
+
self._define_duration_unit(:weeks)
|
219
|
+
self._define_duration_unit(:months)
|
220
|
+
self._define_duration_unit(:years)
|
221
|
+
self._define_duration_unit(:decades)
|
222
|
+
self._define_duration_unit(:centuries)
|
223
|
+
self._define_duration_unit(:millennia)
|
224
|
+
self._define_duration_unit(:second)
|
225
|
+
self._define_duration_unit(:minute)
|
226
|
+
self._define_duration_unit(:hour)
|
227
|
+
self._define_duration_unit(:day)
|
228
|
+
self._define_duration_unit(:week)
|
229
|
+
self._define_duration_unit(:month)
|
230
|
+
self._define_duration_unit(:year)
|
231
|
+
self._define_duration_unit(:decade)
|
232
|
+
self._define_duration_unit(:century)
|
233
|
+
self._define_duration_unit(:millennium)
|
801
234
|
end
|