time_only 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +6 -0
- data/.travis.yml +10 -0
- data/Gemfile +4 -0
- data/LICENSE +22 -0
- data/README.md +59 -0
- data/Rakefile +8 -0
- data/lib/time_only.rb +260 -0
- data/lib/time_only/version.rb +3 -0
- data/spec/time_only_spec.rb +391 -0
- data/time_only.gemspec +21 -0
- metadata +116 -0
data/.gitignore
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2012 OrgSync and Aaron Lasseigne
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,59 @@
|
|
1
|
+
# TimeOnly
|
2
|
+
|
3
|
+
A simple class for handling time and only time. No dates, no time zones, just good old time of day.
|
4
|
+
At the moment, `TimeOnly` only supports resolution to 1 second.
|
5
|
+
|
6
|
+
## Installation
|
7
|
+
|
8
|
+
Add this line to your application's Gemfile:
|
9
|
+
|
10
|
+
gem 'time_only'
|
11
|
+
|
12
|
+
And then execute:
|
13
|
+
|
14
|
+
$ bundle
|
15
|
+
|
16
|
+
Or install it yourself as:
|
17
|
+
|
18
|
+
$ gem install time_only
|
19
|
+
|
20
|
+
## Usage
|
21
|
+
|
22
|
+
`TimeOnly` attempts to implement the same functionality as `Time` where it makes sense to do so.
|
23
|
+
|
24
|
+
require 'time_only'
|
25
|
+
|
26
|
+
time = TimeOnly.new(8, 0, 2)
|
27
|
+
# => '08:00:02'
|
28
|
+
|
29
|
+
time.hour
|
30
|
+
# => 8
|
31
|
+
|
32
|
+
time.min
|
33
|
+
# => 0
|
34
|
+
|
35
|
+
time.sec
|
36
|
+
# => 2
|
37
|
+
|
38
|
+
time.strftime('The time is %-l:%M:%S %P.')
|
39
|
+
# => 'The time is 1:03:56 pm.'
|
40
|
+
|
41
|
+
# adding times rolls the time forward and returns a new TimeOnly
|
42
|
+
TimeOnly.new(23, 59, 59) + 3
|
43
|
+
# => '00:00:02'
|
44
|
+
|
45
|
+
morning_flights, afternoon_flights = departure_times.partition(&:am?)
|
46
|
+
|
47
|
+
current_time = TimeOnly.now
|
48
|
+
|
49
|
+
# and many more...
|
50
|
+
|
51
|
+
Method documentation can be found in the source.
|
52
|
+
|
53
|
+
## Contributing
|
54
|
+
|
55
|
+
1. Fork it
|
56
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
57
|
+
3. Commit your changes (`git commit -am 'Added some feature'`)
|
58
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
59
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
data/lib/time_only.rb
ADDED
@@ -0,0 +1,260 @@
|
|
1
|
+
class TimeOnly
|
2
|
+
include Comparable
|
3
|
+
|
4
|
+
SECONDS_PER_MIN = 60
|
5
|
+
SECONDS_PER_HOUR = 60 * SECONDS_PER_MIN
|
6
|
+
SECONDS_PER_DAY = 24 * SECONDS_PER_HOUR
|
7
|
+
|
8
|
+
# Public: Initialize a TimeOnly.
|
9
|
+
#
|
10
|
+
# seconds - The Integer number of seconds since midnight.
|
11
|
+
#
|
12
|
+
# Examples
|
13
|
+
#
|
14
|
+
# TimeOnly.at(4)
|
15
|
+
# # => '00:00:04'
|
16
|
+
def self.at(seconds)
|
17
|
+
new(seconds)
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.now
|
21
|
+
time = Time.now
|
22
|
+
|
23
|
+
new(time.hour, time.min, time.sec)
|
24
|
+
end
|
25
|
+
|
26
|
+
# Public: Initialize a TimeOnly.
|
27
|
+
#
|
28
|
+
# seconds - The Integer number of seconds since midnight.
|
29
|
+
# OR
|
30
|
+
# hours - The Integer number of hours.
|
31
|
+
# minutes - The Integer number of minutes.
|
32
|
+
# seconds - The Integer number of seconds.
|
33
|
+
#
|
34
|
+
# Examples
|
35
|
+
#
|
36
|
+
# TimeOnly.new(4)
|
37
|
+
# # => '00:00:04'
|
38
|
+
#
|
39
|
+
# TimeOnly.new(13, 24, 56)
|
40
|
+
# # => '13:24:56'
|
41
|
+
def initialize(*args)
|
42
|
+
seconds = case args.size
|
43
|
+
when 1
|
44
|
+
args.first
|
45
|
+
when 3
|
46
|
+
hours, minutes, seconds = args
|
47
|
+
|
48
|
+
raise ArgumentError, 'hours must be between 0 and 23' if hours < 0 || hours > 23
|
49
|
+
raise ArgumentError, 'minutes must be between 0 and 59' if minutes < 0 || minutes > 59
|
50
|
+
raise ArgumentError, 'seconds must be between 0 and 59' if seconds < 0 || seconds > 59
|
51
|
+
|
52
|
+
(hours * SECONDS_PER_HOUR) + (minutes * SECONDS_PER_MIN) + seconds
|
53
|
+
else
|
54
|
+
raise ArgumentError, "wrong number of arguments (#{args.size} for 1 or 3)"
|
55
|
+
end
|
56
|
+
|
57
|
+
@seconds_since_midnight = mod_by_day(seconds)
|
58
|
+
end
|
59
|
+
|
60
|
+
# Public: Add seconds to the time and return that as a new value. If the value
|
61
|
+
# exceeds the number of seconds in a day the time will roll forwardd.
|
62
|
+
#
|
63
|
+
# seconds - The Integer number of seconds.
|
64
|
+
#
|
65
|
+
# Examples
|
66
|
+
#
|
67
|
+
# TimeOnly.new(4) + 3
|
68
|
+
# # => '00:00:07'
|
69
|
+
#
|
70
|
+
# TimeOnly.new(23, 59, 59) + 3
|
71
|
+
# # => '00:00:02'
|
72
|
+
#
|
73
|
+
# Returns a new TimeOnly.
|
74
|
+
def +(seconds)
|
75
|
+
self.class.new(mod_by_day(@seconds_since_midnight + seconds))
|
76
|
+
end
|
77
|
+
|
78
|
+
# Public: Subtract seconds from the time and return that as a new value. If the
|
79
|
+
# value is less than zero seconds in a day the time will roll backwards.
|
80
|
+
#
|
81
|
+
# seconds - The Integer number of seconds.
|
82
|
+
#
|
83
|
+
# Examples
|
84
|
+
#
|
85
|
+
# TimeOnly.new(4) - 3
|
86
|
+
# # => '00:00:01'
|
87
|
+
#
|
88
|
+
# TimeOnly.new(0, 0, 0) - 3
|
89
|
+
# # => '23:59:57'
|
90
|
+
#
|
91
|
+
# Returns a new TimeOnly.
|
92
|
+
def -(seconds)
|
93
|
+
self + (seconds * -1)
|
94
|
+
end
|
95
|
+
|
96
|
+
def ==(other)
|
97
|
+
to_i == other.to_i
|
98
|
+
end
|
99
|
+
alias_method :eql?, :==
|
100
|
+
|
101
|
+
def <=>(other)
|
102
|
+
to_i <=> other.to_i
|
103
|
+
end
|
104
|
+
|
105
|
+
def am?
|
106
|
+
hour < 12
|
107
|
+
end
|
108
|
+
|
109
|
+
def hour
|
110
|
+
@hour ||= @seconds_since_midnight / SECONDS_PER_HOUR
|
111
|
+
end
|
112
|
+
|
113
|
+
def min
|
114
|
+
@min ||= (@seconds_since_midnight % SECONDS_PER_HOUR) / SECONDS_PER_MIN
|
115
|
+
end
|
116
|
+
|
117
|
+
def pm?
|
118
|
+
!am?
|
119
|
+
end
|
120
|
+
|
121
|
+
def sec
|
122
|
+
@sec ||= @seconds_since_midnight % SECONDS_PER_MIN
|
123
|
+
end
|
124
|
+
|
125
|
+
# Public: Formats time according to the directives in the given format string.
|
126
|
+
# The directives begins with a percent (%) character. Any text not listed as a
|
127
|
+
# directive will be passed through to the output string.)
|
128
|
+
#
|
129
|
+
# The directive consists of a percent (%) character, zero or more flags and a
|
130
|
+
# conversion specifier as follows.
|
131
|
+
#
|
132
|
+
# %<flags><conversion>
|
133
|
+
#
|
134
|
+
# Flags:
|
135
|
+
# - don't pad a numerical output
|
136
|
+
#
|
137
|
+
# Directives:
|
138
|
+
# %H - Hour of the day, 24-hour clock, zero-padded (00..23)
|
139
|
+
# %k - Hour of the day, 24-hour clock, blank-padded ( 0..23)
|
140
|
+
# %I - Hour of the day, 12-hour clock, zero-padded (01..12)
|
141
|
+
# %l - Hour of the day, 12-hour clock, blank-padded ( 1..12)
|
142
|
+
# %P - Meridian indicator, lowercase (``am' or ``pm')
|
143
|
+
# %p - Meridian indicator, uppercase (``AM' or ``PM')
|
144
|
+
# %M - Minute of the hour (00..59)
|
145
|
+
# %S - Second of the minute (00..60)
|
146
|
+
#
|
147
|
+
# Literal strings:
|
148
|
+
# %n - Newline character (\n)
|
149
|
+
# %t - Tab character (\t)
|
150
|
+
# %% - Literal ``%'' character)
|
151
|
+
#
|
152
|
+
# Combinations:
|
153
|
+
# %X - Same as %T
|
154
|
+
# %r - 12-hour time (%I:%M:%S %p)
|
155
|
+
# %R - 24-hour time (%H:%M)
|
156
|
+
# %T - 24-hour time (%H:%M:%S)
|
157
|
+
#
|
158
|
+
# format - The String containing directives.
|
159
|
+
#
|
160
|
+
# Examples
|
161
|
+
#
|
162
|
+
# TimeOnly.new(12, 34, 56).strftime('%r')
|
163
|
+
# # => '12:34:56 PM'
|
164
|
+
#
|
165
|
+
# TimeOnly.new(1, 3, 56).strftime('The time is %-l:%M:%S %P.')
|
166
|
+
# # => 'The time is 1:03:56 pm.'
|
167
|
+
#
|
168
|
+
# Returns the formatted String.
|
169
|
+
def strftime(format)
|
170
|
+
format = format.dup
|
171
|
+
|
172
|
+
format.gsub!(/%[rRTX]/) do |token|
|
173
|
+
case token
|
174
|
+
when '%r'
|
175
|
+
'%I:%M:%S %p'
|
176
|
+
when '%R'
|
177
|
+
'%H:%M'
|
178
|
+
when '%T', '%X'
|
179
|
+
'%H:%M:%S'
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
183
|
+
format.gsub(/%-?[HkIlPpMSnt%]/) do |token|
|
184
|
+
case token
|
185
|
+
when '%H'
|
186
|
+
zero_pad(hour)
|
187
|
+
when '%k'
|
188
|
+
blank_pad(hour)
|
189
|
+
when '%-H', '%-k'
|
190
|
+
hour
|
191
|
+
when '%I'
|
192
|
+
zero_pad(twelve_hour)
|
193
|
+
when '%l'
|
194
|
+
blank_pad(twelve_hour)
|
195
|
+
when '%-I', '%-l'
|
196
|
+
twelve_hour
|
197
|
+
when '%P'
|
198
|
+
am? ? 'am' : 'pm'
|
199
|
+
when '%p'
|
200
|
+
am? ? 'AM' : 'PM'
|
201
|
+
when '%M'
|
202
|
+
zero_pad(min)
|
203
|
+
when '%-M'
|
204
|
+
min
|
205
|
+
when '%S'
|
206
|
+
zero_pad(sec)
|
207
|
+
when '%-S'
|
208
|
+
sec
|
209
|
+
when '%n'
|
210
|
+
"\n"
|
211
|
+
when '%t'
|
212
|
+
"\t"
|
213
|
+
when '%%'
|
214
|
+
'%'
|
215
|
+
end
|
216
|
+
end
|
217
|
+
end
|
218
|
+
|
219
|
+
def succ
|
220
|
+
self + 1
|
221
|
+
end
|
222
|
+
|
223
|
+
def to_a
|
224
|
+
[hour, min, sec]
|
225
|
+
end
|
226
|
+
|
227
|
+
def to_f
|
228
|
+
@seconds_since_midnight.to_f
|
229
|
+
end
|
230
|
+
|
231
|
+
def to_i
|
232
|
+
@seconds_since_midnight
|
233
|
+
end
|
234
|
+
alias_method :tv_sec, :to_i
|
235
|
+
|
236
|
+
def to_s
|
237
|
+
strftime('%T')
|
238
|
+
end
|
239
|
+
alias_method :asctime, :to_s
|
240
|
+
alias_method :ctime, :to_s
|
241
|
+
alias_method :inspect, :to_s
|
242
|
+
|
243
|
+
private
|
244
|
+
|
245
|
+
def mod_by_day(seconds)
|
246
|
+
seconds % SECONDS_PER_DAY
|
247
|
+
end
|
248
|
+
|
249
|
+
def twelve_hour
|
250
|
+
hour > 12 ? hour % 12 : hour
|
251
|
+
end
|
252
|
+
|
253
|
+
def zero_pad(number)
|
254
|
+
number < 10 ? "0#{number}" : number
|
255
|
+
end
|
256
|
+
|
257
|
+
def blank_pad(number)
|
258
|
+
number < 10 ? " #{number}" : number
|
259
|
+
end
|
260
|
+
end
|
@@ -0,0 +1,391 @@
|
|
1
|
+
require 'rspec'
|
2
|
+
require 'timecop'
|
3
|
+
require 'time_only'
|
4
|
+
|
5
|
+
describe TimeOnly do
|
6
|
+
describe '.new(args)' do
|
7
|
+
context 'one arg' do
|
8
|
+
it 'creates as the seconds since midnight' do
|
9
|
+
expect(described_class.new(45296).to_i).to eq(45296)
|
10
|
+
end
|
11
|
+
|
12
|
+
it "rolls over seconds that are greater than #{described_class::SECONDS_PER_DAY}" do
|
13
|
+
expect(described_class.new(described_class::SECONDS_PER_DAY * 2 + 1).to_i).to eq(1)
|
14
|
+
end
|
15
|
+
|
16
|
+
it 'handles negative seconds which rolls back' do
|
17
|
+
expect(described_class.new(-10).to_i).to eq(described_class::SECONDS_PER_DAY - 10)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
context 'three argss' do
|
22
|
+
it 'creates based on hours, minutes and seconds' do
|
23
|
+
expect(described_class.new(12, 34, 56).to_i).to eq(45296)
|
24
|
+
end
|
25
|
+
|
26
|
+
it 'raises an error when the hours arg is outside of 0 - 23' do
|
27
|
+
expect{ described_class.new(24, 0, 0) }.to raise_error(ArgumentError)
|
28
|
+
end
|
29
|
+
|
30
|
+
it 'raises an error when the minutes arg is outside of 0 - 59' do
|
31
|
+
expect{ described_class.new(0, 60, 0) }.to raise_error(ArgumentError)
|
32
|
+
end
|
33
|
+
|
34
|
+
it 'raises an error when the seconds arg is outside of 0 - 59' do
|
35
|
+
expect{ described_class.new(0, 0, 60) }.to raise_error(ArgumentError)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
it 'raises an error when the wrong number of arguments is passed' do
|
40
|
+
expect{ described_class.new(1, 2) }.to raise_error(ArgumentError)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
describe '.at(seconds)' do
|
45
|
+
it 'creates a time based on the number of seconds since midnight' do
|
46
|
+
expect(described_class.at(300).to_i).to eq(300)
|
47
|
+
end
|
48
|
+
|
49
|
+
it "rolls over seconds that are greater than #{described_class::SECONDS_PER_DAY}" do
|
50
|
+
expect(described_class.at(described_class::SECONDS_PER_DAY * 2 + 1).to_i).to eq(1)
|
51
|
+
end
|
52
|
+
|
53
|
+
it 'handles negative seconds which rolls back' do
|
54
|
+
expect(described_class.at(-10).to_i).to eq(described_class::SECONDS_PER_DAY - 10)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
describe '.now' do
|
59
|
+
it "returns a #{described_class} object for the current system time" do
|
60
|
+
hour, min, sec = 12, 34, 56
|
61
|
+
|
62
|
+
Timecop.freeze(Time.local(2012, 11, 30, hour, min, sec)) do
|
63
|
+
expect(described_class.now.to_s).to eq("#{hour}:#{min}:#{sec}")
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
describe '#+(seconds)' do
|
69
|
+
it "returns a new #{described_class} object with n seconds added to it" do
|
70
|
+
current_time = described_class.new(0)
|
71
|
+
new_time = current_time + 1
|
72
|
+
|
73
|
+
expect(current_time).not_to equal(new_time)
|
74
|
+
expect(new_time).to eq(described_class.new(1))
|
75
|
+
end
|
76
|
+
|
77
|
+
it 'rolls over time when greater than 23:59:59' do
|
78
|
+
expect(described_class.new(23, 59, 59) + 2).to eq(described_class.new(0, 0, 1))
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
describe '#-(seconds)' do
|
83
|
+
it "returns a new #{described_class} object with n seconds subtracted from it" do
|
84
|
+
current_time = described_class.new(1)
|
85
|
+
new_time = current_time - 1
|
86
|
+
|
87
|
+
expect(current_time).not_to equal(new_time)
|
88
|
+
expect(new_time).to eq(described_class.new(0))
|
89
|
+
end
|
90
|
+
|
91
|
+
it 'rolls back time when less than 00:00:00' do
|
92
|
+
expect(described_class.new(00, 00, 01) - 2).to eq(described_class.new(23, 59, 59))
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
describe '#==(other)' do # aliases: eql?
|
97
|
+
it 'returns true when the times are the same' do
|
98
|
+
expect(described_class.new(12, 34, 56) == described_class.new(12, 34, 56)).to be_true
|
99
|
+
end
|
100
|
+
|
101
|
+
it 'returns false when the times are not the same' do
|
102
|
+
expect(described_class.new(12, 34, 56) == described_class.new(0, 0, 0)).to be_false
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
describe '#<=>(other)' do
|
107
|
+
it 'returns 0 when the times are equal' do
|
108
|
+
other = described_class.new(0)
|
109
|
+
|
110
|
+
expect(described_class.new(0) <=> other).to eq(0)
|
111
|
+
end
|
112
|
+
|
113
|
+
it 'returns -1 when the times are equal' do
|
114
|
+
other = described_class.new(1)
|
115
|
+
|
116
|
+
expect(described_class.new(0) <=> other).to eq(-1)
|
117
|
+
end
|
118
|
+
|
119
|
+
it 'returns 1 when the times are equal' do
|
120
|
+
other = described_class.new(0)
|
121
|
+
|
122
|
+
expect(described_class.new(1) <=> other).to eq(1)
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
describe '#am?' do
|
127
|
+
context 'time is before noon' do
|
128
|
+
subject { described_class.new(2, 4, 6) }
|
129
|
+
|
130
|
+
its(:am?) { should be_true }
|
131
|
+
end
|
132
|
+
|
133
|
+
context 'time is after noon' do
|
134
|
+
subject { described_class.new(12, 4, 6) }
|
135
|
+
|
136
|
+
its(:am?) { should be_false }
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
describe '#hour' do
|
141
|
+
subject { described_class.new(2, 4, 6) }
|
142
|
+
|
143
|
+
its(:hour) { should be 2 }
|
144
|
+
end
|
145
|
+
|
146
|
+
describe '#min' do
|
147
|
+
subject { described_class.new(2, 4, 6) }
|
148
|
+
|
149
|
+
its(:min) { should be 4 }
|
150
|
+
end
|
151
|
+
|
152
|
+
describe '#pm?' do
|
153
|
+
context 'time is before noon' do
|
154
|
+
subject { described_class.new(2, 4, 6) }
|
155
|
+
|
156
|
+
its(:pm?) { should be_false }
|
157
|
+
end
|
158
|
+
|
159
|
+
context 'time is after noon' do
|
160
|
+
subject { described_class.new(12, 4, 6) }
|
161
|
+
|
162
|
+
its(:pm?) { should be_true }
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
describe '#sec' do
|
167
|
+
subject { described_class.new(2, 4, 6) }
|
168
|
+
|
169
|
+
its(:sec) { should be 6 }
|
170
|
+
end
|
171
|
+
|
172
|
+
describe '#strftime' do
|
173
|
+
context 'flags' do
|
174
|
+
context "- don't pad a numerical output" do
|
175
|
+
context 'hour' do
|
176
|
+
%w(H k I l).each do |directive|
|
177
|
+
context "using %#{directive}" do
|
178
|
+
it 'hour is one digit' do
|
179
|
+
expect(described_class.new(8, 0, 0).strftime("%-#{directive}")).to eq('8')
|
180
|
+
end
|
181
|
+
|
182
|
+
it 'hour is two digits' do
|
183
|
+
if directive == 'I' || directive == 'l'
|
184
|
+
hour, hour_s = 13, '1'
|
185
|
+
else
|
186
|
+
hour, hour_s = 12, '12'
|
187
|
+
end
|
188
|
+
|
189
|
+
expect(described_class.new(hour, 0, 0).strftime("%-#{directive}")).to eq(hour_s)
|
190
|
+
end
|
191
|
+
end
|
192
|
+
end
|
193
|
+
end
|
194
|
+
|
195
|
+
context 'min' do
|
196
|
+
it 'min is one digit' do
|
197
|
+
expect(described_class.new(0, 8, 0).strftime('%-M')).to eq('8')
|
198
|
+
end
|
199
|
+
|
200
|
+
it 'min is two digits' do
|
201
|
+
expect(described_class.new(0, 12, 0).strftime('%-M')).to eq('12')
|
202
|
+
end
|
203
|
+
end
|
204
|
+
|
205
|
+
context 'sec' do
|
206
|
+
it 'sec is one digit' do
|
207
|
+
expect(described_class.new(0, 0, 8).strftime('%-S')).to eq('8')
|
208
|
+
end
|
209
|
+
|
210
|
+
it 'sec is two digits' do
|
211
|
+
expect(described_class.new(0, 0, 12).strftime('%-S')).to eq('12')
|
212
|
+
end
|
213
|
+
end
|
214
|
+
end
|
215
|
+
end
|
216
|
+
|
217
|
+
context 'directives' do
|
218
|
+
context '%H - Hour of the day, 24-hour clock, zero-padded (00..23)' do
|
219
|
+
it 'hour is one digit' do
|
220
|
+
expect(described_class.new(8, 0, 0).strftime('%H')).to eq('08')
|
221
|
+
end
|
222
|
+
|
223
|
+
it 'hour is two digits' do
|
224
|
+
expect(described_class.new(12, 0, 0).strftime('%H')).to eq('12')
|
225
|
+
end
|
226
|
+
end
|
227
|
+
|
228
|
+
context '%k - Hour of the day, 24-hour clock, blank-padded ( 0..23)' do
|
229
|
+
it 'hour is one digit' do
|
230
|
+
expect(described_class.new(8, 0, 0).strftime('%k')).to eq(' 8')
|
231
|
+
end
|
232
|
+
|
233
|
+
it 'hour is two digits' do
|
234
|
+
expect(described_class.new(12, 0, 0).strftime('%k')).to eq('12')
|
235
|
+
end
|
236
|
+
end
|
237
|
+
|
238
|
+
context '%I - Hour of the day, 12-hour clock, zero-padded (01..12)' do
|
239
|
+
context 'before 1pm' do
|
240
|
+
it 'hour is one digit' do
|
241
|
+
expect(described_class.new(8, 0, 0).strftime('%I')).to eq('08')
|
242
|
+
end
|
243
|
+
|
244
|
+
it 'hour is two digits' do
|
245
|
+
expect(described_class.new(12, 0, 0).strftime('%I')).to eq('12')
|
246
|
+
end
|
247
|
+
end
|
248
|
+
|
249
|
+
context 'after or equal to 1pm' do
|
250
|
+
it 'hour is one digit' do
|
251
|
+
expect(described_class.new(13, 0, 0).strftime('%I')).to eq('01')
|
252
|
+
end
|
253
|
+
|
254
|
+
it 'hour is two digits' do
|
255
|
+
expect(described_class.new(22, 0, 0).strftime('%I')).to eq('10')
|
256
|
+
end
|
257
|
+
end
|
258
|
+
end
|
259
|
+
|
260
|
+
context '%l - Hour of the day, 12-hour clock, blank-padded ( 1..12)' do
|
261
|
+
context 'before 1pm' do
|
262
|
+
it 'hour is one digit' do
|
263
|
+
expect(described_class.new(8, 0, 0).strftime('%l')).to eq(' 8')
|
264
|
+
end
|
265
|
+
|
266
|
+
it 'hour is two digits' do
|
267
|
+
expect(described_class.new(12, 0, 0).strftime('%l')).to eq('12')
|
268
|
+
end
|
269
|
+
end
|
270
|
+
|
271
|
+
context 'after or equal to 1pm' do
|
272
|
+
it 'hour is one digit' do
|
273
|
+
expect(described_class.new(13, 0, 0).strftime('%l')).to eq(' 1')
|
274
|
+
end
|
275
|
+
|
276
|
+
it 'hour is two digits' do
|
277
|
+
expect(described_class.new(22, 0, 0).strftime('%l')).to eq('10')
|
278
|
+
end
|
279
|
+
end
|
280
|
+
end
|
281
|
+
|
282
|
+
context '%P - Meridian indicator, lowercase ("am" or "pm")' do
|
283
|
+
it 'hours are before noon' do
|
284
|
+
expect(described_class.new(8, 0, 0).strftime('%P')).to eq('am')
|
285
|
+
end
|
286
|
+
|
287
|
+
it 'hours are after noon' do
|
288
|
+
expect(described_class.new(13, 0, 0).strftime('%P')).to eq('pm')
|
289
|
+
end
|
290
|
+
end
|
291
|
+
|
292
|
+
context '%p - Meridian indicator, uppercase ("AM" or "PM")' do
|
293
|
+
it 'hours are before noon' do
|
294
|
+
expect(described_class.new(8, 0, 0).strftime('%p')).to eq('AM')
|
295
|
+
end
|
296
|
+
|
297
|
+
it 'hours are after noon' do
|
298
|
+
expect(described_class.new(13, 0, 0).strftime('%p')).to eq('PM')
|
299
|
+
end
|
300
|
+
end
|
301
|
+
|
302
|
+
context '%M - Minute of the hour (00..59)' do
|
303
|
+
it 'min is one digit' do
|
304
|
+
expect(described_class.new(0, 8, 0).strftime('%M')).to eq('08')
|
305
|
+
end
|
306
|
+
|
307
|
+
it 'min is two digits' do
|
308
|
+
expect(described_class.new(0, 12, 0).strftime('%M')).to eq('12')
|
309
|
+
end
|
310
|
+
end
|
311
|
+
|
312
|
+
context '%S - Second of the minute (00..60)' do
|
313
|
+
it 'sec is one digit' do
|
314
|
+
expect(described_class.new(0, 0, 8).strftime('%S')).to eq('08')
|
315
|
+
end
|
316
|
+
|
317
|
+
it 'sec is two digits' do
|
318
|
+
expect(described_class.new(0, 0, 12).strftime('%S')).to eq('12')
|
319
|
+
end
|
320
|
+
end
|
321
|
+
end
|
322
|
+
|
323
|
+
context 'literals' do
|
324
|
+
it '%n - Newline character (\n)' do
|
325
|
+
expect(described_class.at(0).strftime('%n')).to eq("\n")
|
326
|
+
end
|
327
|
+
|
328
|
+
it '%t - Tab character (\t)' do
|
329
|
+
expect(described_class.at(0).strftime('%t')).to eq("\t")
|
330
|
+
end
|
331
|
+
|
332
|
+
it '%% - Literal "%" character' do
|
333
|
+
expect(described_class.at(0).strftime('%%')).to eq('%')
|
334
|
+
end
|
335
|
+
end
|
336
|
+
|
337
|
+
context 'combinations' do
|
338
|
+
it '%r - 12-hour time (%I:%M:%S %p)' do
|
339
|
+
expect(described_class.new(1, 0, 12).strftime('%r')).to eq('01:00:12 AM')
|
340
|
+
end
|
341
|
+
|
342
|
+
it '%R - 24-hour time (%H:%M)' do
|
343
|
+
expect(described_class.new(1, 0, 12).strftime('%R')).to eq('01:00')
|
344
|
+
end
|
345
|
+
|
346
|
+
%w(X T).each do |combination|
|
347
|
+
it "%#{combination} - 24-hour time (%H:%M:%S)" do
|
348
|
+
expect(described_class.new(1, 0, 12).strftime("%#{combination}")).to eq('01:00:12')
|
349
|
+
end
|
350
|
+
end
|
351
|
+
end
|
352
|
+
end
|
353
|
+
|
354
|
+
describe '#succ' do
|
355
|
+
it "returns a new #{described_class} object, one second later than the original" do
|
356
|
+
current_time = described_class.new(0)
|
357
|
+
new_time = current_time.succ
|
358
|
+
|
359
|
+
expect(current_time).not_to equal(new_time)
|
360
|
+
expect(new_time).to eq(described_class.new(1))
|
361
|
+
end
|
362
|
+
|
363
|
+
it 'rolls over time when greater than 23:59:59' do
|
364
|
+
expect(described_class.new(23, 59, 59).succ).to eq(described_class.new(0, 0, 0))
|
365
|
+
end
|
366
|
+
end
|
367
|
+
|
368
|
+
describe '#to_a' do
|
369
|
+
subject { described_class.new(2, 3, 4) }
|
370
|
+
|
371
|
+
its(:to_a) { should == [2, 3, 4] }
|
372
|
+
end
|
373
|
+
|
374
|
+
describe '#to_f' do
|
375
|
+
subject { described_class.new(300) }
|
376
|
+
|
377
|
+
its(:to_f) { should == 300.0 }
|
378
|
+
end
|
379
|
+
|
380
|
+
describe '#to_i' do # aliases: tv_sec
|
381
|
+
subject { described_class.new(300) }
|
382
|
+
|
383
|
+
its(:to_i) { should == 300 }
|
384
|
+
end
|
385
|
+
|
386
|
+
describe '#to_s' do # aliases: asctime, ctime, inspect
|
387
|
+
subject { described_class.new(2, 4, 6) }
|
388
|
+
|
389
|
+
its(:to_s) { should == '02:04:06' }
|
390
|
+
end
|
391
|
+
end
|
data/time_only.gemspec
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
require File.expand_path('../lib/time_only/version', __FILE__)
|
3
|
+
|
4
|
+
Gem::Specification.new do |gem|
|
5
|
+
gem.name = 'time_only'
|
6
|
+
gem.version = TimeOnly::VERSION
|
7
|
+
gem.summary = 'A simple class for handling time and only time.'
|
8
|
+
gem.description = "#{gem.summary} No dates, no time zones, just good old time of day."
|
9
|
+
|
10
|
+
gem.authors = ['Aaron Lasseigne']
|
11
|
+
gem.email = ['aaron@orgsync.com']
|
12
|
+
|
13
|
+
gem.files = `git ls-files`.split($\)
|
14
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
15
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
16
|
+
gem.require_paths = ['lib']
|
17
|
+
|
18
|
+
gem.add_development_dependency 'rake'
|
19
|
+
gem.add_development_dependency 'rspec'
|
20
|
+
gem.add_development_dependency 'timecop'
|
21
|
+
end
|
metadata
ADDED
@@ -0,0 +1,116 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: time_only
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 23
|
5
|
+
prerelease:
|
6
|
+
segments:
|
7
|
+
- 1
|
8
|
+
- 0
|
9
|
+
- 0
|
10
|
+
version: 1.0.0
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- Aaron Lasseigne
|
14
|
+
autorequire:
|
15
|
+
bindir: bin
|
16
|
+
cert_chain: []
|
17
|
+
|
18
|
+
date: 2012-12-04 00:00:00 Z
|
19
|
+
dependencies:
|
20
|
+
- !ruby/object:Gem::Dependency
|
21
|
+
name: rake
|
22
|
+
version_requirements: &id001 !ruby/object:Gem::Requirement
|
23
|
+
none: false
|
24
|
+
requirements:
|
25
|
+
- - ">="
|
26
|
+
- !ruby/object:Gem::Version
|
27
|
+
hash: 3
|
28
|
+
segments:
|
29
|
+
- 0
|
30
|
+
version: "0"
|
31
|
+
type: :development
|
32
|
+
requirement: *id001
|
33
|
+
prerelease: false
|
34
|
+
- !ruby/object:Gem::Dependency
|
35
|
+
name: rspec
|
36
|
+
version_requirements: &id002 !ruby/object:Gem::Requirement
|
37
|
+
none: false
|
38
|
+
requirements:
|
39
|
+
- - ">="
|
40
|
+
- !ruby/object:Gem::Version
|
41
|
+
hash: 3
|
42
|
+
segments:
|
43
|
+
- 0
|
44
|
+
version: "0"
|
45
|
+
type: :development
|
46
|
+
requirement: *id002
|
47
|
+
prerelease: false
|
48
|
+
- !ruby/object:Gem::Dependency
|
49
|
+
name: timecop
|
50
|
+
version_requirements: &id003 !ruby/object:Gem::Requirement
|
51
|
+
none: false
|
52
|
+
requirements:
|
53
|
+
- - ">="
|
54
|
+
- !ruby/object:Gem::Version
|
55
|
+
hash: 3
|
56
|
+
segments:
|
57
|
+
- 0
|
58
|
+
version: "0"
|
59
|
+
type: :development
|
60
|
+
requirement: *id003
|
61
|
+
prerelease: false
|
62
|
+
description: A simple class for handling time and only time. No dates, no time zones, just good old time of day.
|
63
|
+
email:
|
64
|
+
- aaron@orgsync.com
|
65
|
+
executables: []
|
66
|
+
|
67
|
+
extensions: []
|
68
|
+
|
69
|
+
extra_rdoc_files: []
|
70
|
+
|
71
|
+
files:
|
72
|
+
- .gitignore
|
73
|
+
- .travis.yml
|
74
|
+
- Gemfile
|
75
|
+
- LICENSE
|
76
|
+
- README.md
|
77
|
+
- Rakefile
|
78
|
+
- lib/time_only.rb
|
79
|
+
- lib/time_only/version.rb
|
80
|
+
- spec/time_only_spec.rb
|
81
|
+
- time_only.gemspec
|
82
|
+
homepage:
|
83
|
+
licenses: []
|
84
|
+
|
85
|
+
post_install_message:
|
86
|
+
rdoc_options: []
|
87
|
+
|
88
|
+
require_paths:
|
89
|
+
- lib
|
90
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
91
|
+
none: false
|
92
|
+
requirements:
|
93
|
+
- - ">="
|
94
|
+
- !ruby/object:Gem::Version
|
95
|
+
hash: 3
|
96
|
+
segments:
|
97
|
+
- 0
|
98
|
+
version: "0"
|
99
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
100
|
+
none: false
|
101
|
+
requirements:
|
102
|
+
- - ">="
|
103
|
+
- !ruby/object:Gem::Version
|
104
|
+
hash: 3
|
105
|
+
segments:
|
106
|
+
- 0
|
107
|
+
version: "0"
|
108
|
+
requirements: []
|
109
|
+
|
110
|
+
rubyforge_project:
|
111
|
+
rubygems_version: 1.8.24
|
112
|
+
signing_key:
|
113
|
+
specification_version: 3
|
114
|
+
summary: A simple class for handling time and only time.
|
115
|
+
test_files:
|
116
|
+
- spec/time_only_spec.rb
|