ice_cube 0.16.0 → 0.16.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/config/locales/de.yml +1 -1
- data/config/locales/en.yml +7 -46
- data/config/locales/es.yml +47 -83
- data/config/locales/fr.yml +2 -2
- data/config/locales/it.yml +179 -0
- data/config/locales/ja.yml +52 -29
- data/config/locales/nl.yml +133 -0
- data/config/locales/pt-BR.yml +178 -0
- data/config/locales/sv.yml +1 -1
- data/lib/ice_cube/i18n.rb +11 -12
- data/lib/ice_cube/input_alignment.rb +89 -0
- data/lib/ice_cube/null_i18n.rb +12 -6
- data/lib/ice_cube/occurrence.rb +25 -23
- data/lib/ice_cube/parsers/ical_parser.rb +8 -5
- data/lib/ice_cube/rule.rb +5 -13
- data/lib/ice_cube/rules/daily_rule.rb +9 -0
- data/lib/ice_cube/rules/hourly_rule.rb +9 -0
- data/lib/ice_cube/rules/minutely_rule.rb +9 -0
- data/lib/ice_cube/rules/monthly_rule.rb +9 -0
- data/lib/ice_cube/rules/secondly_rule.rb +9 -0
- data/lib/ice_cube/rules/weekly_rule.rb +30 -9
- data/lib/ice_cube/rules/yearly_rule.rb +9 -0
- data/lib/ice_cube/schedule.rb +30 -29
- data/lib/ice_cube/single_occurrence_rule.rb +4 -0
- data/lib/ice_cube/time_util.rb +65 -46
- data/lib/ice_cube/validated_rule.rb +18 -24
- data/lib/ice_cube/validations/count.rb +1 -2
- data/lib/ice_cube/validations/daily_interval.rb +5 -1
- data/lib/ice_cube/validations/day.rb +6 -2
- data/lib/ice_cube/validations/day_of_month.rb +5 -0
- data/lib/ice_cube/validations/day_of_week.rb +1 -1
- data/lib/ice_cube/validations/hour_of_day.rb +23 -0
- data/lib/ice_cube/validations/hourly_interval.rb +2 -0
- data/lib/ice_cube/validations/minute_of_hour.rb +16 -0
- data/lib/ice_cube/validations/minutely_interval.rb +2 -0
- data/lib/ice_cube/validations/month_of_year.rb +6 -1
- data/lib/ice_cube/validations/monthly_interval.rb +4 -1
- data/lib/ice_cube/validations/schedule_lock.rb +4 -0
- data/lib/ice_cube/validations/second_of_minute.rb +19 -3
- data/lib/ice_cube/validations/secondly_interval.rb +2 -0
- data/lib/ice_cube/validations/until.rb +1 -2
- data/lib/ice_cube/validations/weekly_interval.rb +0 -2
- data/lib/ice_cube/version.rb +1 -1
- data/lib/ice_cube.rb +1 -3
- data/spec/spec_helper.rb +32 -9
- metadata +10 -7
data/lib/ice_cube/schedule.rb
CHANGED
@@ -340,9 +340,9 @@ module IceCube
|
|
340
340
|
IcalParser.schedule_from_ical(ical, options)
|
341
341
|
end
|
342
342
|
|
343
|
-
#
|
344
|
-
def
|
345
|
-
|
343
|
+
# Hook for YAML.dump, enables to_yaml
|
344
|
+
def encode_with(coder)
|
345
|
+
coder.represent_object nil, to_hash
|
346
346
|
end
|
347
347
|
|
348
348
|
# Load the schedule from yaml
|
@@ -371,6 +371,7 @@ module IceCube
|
|
371
371
|
end
|
372
372
|
data
|
373
373
|
end
|
374
|
+
alias_method :to_h, :to_hash
|
374
375
|
|
375
376
|
# Load the schedule from a hash
|
376
377
|
def self.from_hash(original_hash, options = {})
|
@@ -383,9 +384,22 @@ module IceCube
|
|
383
384
|
# Determine if the schedule will end
|
384
385
|
# @return [Boolean] true if ending, false if repeating forever
|
385
386
|
def terminating?
|
386
|
-
|
387
|
+
@all_recurrence_rules.all?(&:terminating?)
|
387
388
|
end
|
388
389
|
|
390
|
+
def hash
|
391
|
+
[
|
392
|
+
TimeUtil.hash(start_time), duration,
|
393
|
+
*@all_recurrence_rules.map(&:hash).sort!,
|
394
|
+
*@all_exception_rules.map(&:hash).sort!
|
395
|
+
].hash
|
396
|
+
end
|
397
|
+
|
398
|
+
def eql?(other)
|
399
|
+
self.hash == other.hash
|
400
|
+
end
|
401
|
+
alias == eql?
|
402
|
+
|
389
403
|
def self.dump(schedule)
|
390
404
|
return schedule if schedule.nil? || schedule == ""
|
391
405
|
schedule.to_yaml
|
@@ -407,31 +421,24 @@ module IceCube
|
|
407
421
|
# Find all of the occurrences for the schedule between opening_time
|
408
422
|
# and closing_time
|
409
423
|
# Iteration is unrolled in pairs to skip duplicate times in end of DST
|
410
|
-
def enumerate_occurrences(opening_time, closing_time = nil, options = {}
|
424
|
+
def enumerate_occurrences(opening_time, closing_time = nil, options = {})
|
411
425
|
opening_time = TimeUtil.match_zone(opening_time, start_time)
|
412
426
|
closing_time = TimeUtil.match_zone(closing_time, start_time)
|
413
|
-
opening_time +=
|
427
|
+
opening_time += TimeUtil.subsec(start_time) - TimeUtil.subsec(opening_time)
|
414
428
|
opening_time = start_time if opening_time < start_time
|
415
429
|
spans = options[:spans] == true && duration != 0
|
416
430
|
Enumerator.new do |yielder|
|
417
431
|
reset
|
418
|
-
t1 = full_required? ? start_time : opening_time
|
432
|
+
t1 = full_required? ? start_time : opening_time
|
433
|
+
t1 -= duration if spans
|
434
|
+
t1 = start_time if t1 < start_time
|
419
435
|
loop do
|
420
436
|
break unless (t0 = next_time(t1, closing_time))
|
421
437
|
break if closing_time && t0 > closing_time
|
422
438
|
if (spans ? (t0.end_time > opening_time) : (t0 >= opening_time))
|
423
|
-
yielder << (block_given? ?
|
424
|
-
end
|
425
|
-
break unless (t1 = next_time(t0 + 1, closing_time))
|
426
|
-
break if closing_time && t1 > closing_time
|
427
|
-
if TimeUtil.same_clock?(t0, t1) && recurrence_rules.any?(&:dst_adjust?)
|
428
|
-
wind_back_dst
|
429
|
-
next (t1 += 1)
|
439
|
+
yielder << (block_given? ? yield(t0) : t0)
|
430
440
|
end
|
431
|
-
|
432
|
-
yielder << (block_given? ? block.call(t1) : t1)
|
433
|
-
end
|
434
|
-
next (t1 += 1)
|
441
|
+
t1 = t0 + 1
|
435
442
|
end
|
436
443
|
end
|
437
444
|
end
|
@@ -439,15 +446,15 @@ module IceCube
|
|
439
446
|
# Get the next time after (or including) a specific time
|
440
447
|
def next_time(time, closing_time)
|
441
448
|
loop do
|
442
|
-
min_time = recurrence_rules_with_implicit_start_occurrence.reduce(nil) do |
|
449
|
+
min_time = recurrence_rules_with_implicit_start_occurrence.reduce(nil) do |best_time, rule|
|
443
450
|
begin
|
444
|
-
new_time = rule.next_time(time, start_time,
|
445
|
-
[
|
451
|
+
new_time = rule.next_time(time, start_time, best_time || closing_time)
|
452
|
+
[best_time, new_time].compact.min
|
446
453
|
rescue StopIteration
|
447
|
-
|
454
|
+
best_time
|
448
455
|
end
|
449
456
|
end
|
450
|
-
break
|
457
|
+
break unless min_time
|
451
458
|
next (time = min_time + 1) if exception_time?(min_time)
|
452
459
|
break Occurrence.new(min_time, min_time + duration)
|
453
460
|
end
|
@@ -498,12 +505,6 @@ module IceCube
|
|
498
505
|
end
|
499
506
|
end
|
500
507
|
|
501
|
-
def wind_back_dst
|
502
|
-
recurrence_rules.each do |rule|
|
503
|
-
rule.skipped_for_dst
|
504
|
-
end
|
505
|
-
end
|
506
|
-
|
507
508
|
end
|
508
509
|
|
509
510
|
end
|
data/lib/ice_cube/time_util.rb
CHANGED
@@ -47,7 +47,7 @@ module IceCube
|
|
47
47
|
time.in_time_zone(reference.time_zone)
|
48
48
|
else
|
49
49
|
if reference.utc?
|
50
|
-
time.
|
50
|
+
time.getgm
|
51
51
|
elsif reference.zone
|
52
52
|
time.getlocal
|
53
53
|
else
|
@@ -89,18 +89,27 @@ module IceCube
|
|
89
89
|
|
90
90
|
# Serialize a time appropriate for storing
|
91
91
|
def self.serialize_time(time)
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
92
|
+
case time
|
93
|
+
when Time, Date
|
94
|
+
if time.respond_to?(:time_zone)
|
95
|
+
{:time => time.utc, :zone => time.time_zone.name}
|
96
|
+
else
|
97
|
+
time
|
98
|
+
end
|
99
|
+
when DateTime
|
100
|
+
Time.local(time.year, time.month, time.day, time.hour, time.min, time.sec)
|
101
|
+
else
|
102
|
+
raise ArgumentError, "cannot serialize #{time.inspect}, expected a Time"
|
96
103
|
end
|
97
104
|
end
|
98
105
|
|
99
106
|
# Deserialize a time serialized with serialize_time or in ISO8601 string format
|
100
107
|
def self.deserialize_time(time_or_hash)
|
101
108
|
case time_or_hash
|
102
|
-
when Time
|
109
|
+
when Time, Date
|
103
110
|
time_or_hash
|
111
|
+
when DateTime
|
112
|
+
Time.local(time.year, time.month, time.day, time.hour, time.min, time.sec)
|
104
113
|
when Hash
|
105
114
|
hash = FlexibleHash.new(time_or_hash)
|
106
115
|
hash[:time].in_time_zone(hash[:zone])
|
@@ -109,6 +118,14 @@ module IceCube
|
|
109
118
|
end
|
110
119
|
end
|
111
120
|
|
121
|
+
# Get a more precise equality for time objects
|
122
|
+
# Ruby provides a Time#hash method, but it fails to account for UTC
|
123
|
+
# offset (so the current date may be different) or DST rules (so the
|
124
|
+
# hour may be wrong for different schedule occurrences)
|
125
|
+
def self.hash(time)
|
126
|
+
[time, time.utc_offset, time.zone].hash
|
127
|
+
end
|
128
|
+
|
112
129
|
# Check the deserialized time offset string against actual local time
|
113
130
|
# offset to try and preserve the original offset for plain Ruby Time. If
|
114
131
|
# the offset is the same as local we can assume the same original zone and
|
@@ -153,20 +170,13 @@ module IceCube
|
|
153
170
|
|
154
171
|
# Convert wday number to day symbol
|
155
172
|
def self.wday_to_sym(wday)
|
156
|
-
return
|
173
|
+
return wday if DAYS.keys.include? wday
|
157
174
|
DAYS.invert.fetch(wday) do |i|
|
158
175
|
raise ArgumentError, "Expecting Integer value for weekday. " \
|
159
176
|
"No such wday number: #{i.inspect}"
|
160
177
|
end
|
161
178
|
end
|
162
179
|
|
163
|
-
# Convert a symbol to an ical day (SU, MO)
|
164
|
-
def self.week_start(sym)
|
165
|
-
raise ArgumentError, "Invalid day: #{str}" unless DAYS.keys.include?(sym)
|
166
|
-
day = sym.to_s.upcase[0..1]
|
167
|
-
day
|
168
|
-
end
|
169
|
-
|
170
180
|
# Convert weekday from base sunday to the schedule's week start.
|
171
181
|
def self.normalize_wday(wday, week_start)
|
172
182
|
(wday - sym_to_wday(week_start)) % 7
|
@@ -243,8 +253,19 @@ module IceCube
|
|
243
253
|
end
|
244
254
|
end
|
245
255
|
|
246
|
-
|
247
|
-
|
256
|
+
# Handle discrepancies between various time types
|
257
|
+
# - Time has subsec
|
258
|
+
# - DateTime does not
|
259
|
+
# - ActiveSupport::TimeWithZone can wrap either type, depending on version
|
260
|
+
# or if `parse` or `now`/`local` was used to build it.
|
261
|
+
def self.subsec(time)
|
262
|
+
if time.respond_to?(:subsec)
|
263
|
+
time.subsec
|
264
|
+
elsif time.respond_to?(:sec_fraction)
|
265
|
+
time.sec_fraction
|
266
|
+
else
|
267
|
+
0.0
|
268
|
+
end
|
248
269
|
end
|
249
270
|
|
250
271
|
# A utility class for safely moving time around
|
@@ -252,27 +273,32 @@ module IceCube
|
|
252
273
|
|
253
274
|
def initialize(time, dst_adjust = true)
|
254
275
|
@dst_adjust = dst_adjust
|
255
|
-
@
|
276
|
+
@base = time
|
277
|
+
if dst_adjust
|
278
|
+
@time = Time.utc(time.year, time.month, time.day, time.hour, time.min, time.sec + TimeUtil.subsec(time))
|
279
|
+
else
|
280
|
+
@time = time
|
281
|
+
end
|
256
282
|
end
|
257
283
|
|
258
|
-
# Get the
|
284
|
+
# Get the wrapped time back in its original zone & format
|
259
285
|
def to_time
|
260
|
-
@time
|
286
|
+
return @time unless @dst_adjust
|
287
|
+
parts = @time.year, @time.month, @time.day, @time.hour, @time.min, @time.sec + @time.subsec
|
288
|
+
TimeUtil.build_in_zone(parts, @base)
|
261
289
|
end
|
262
290
|
|
263
291
|
# DST-safely add an interval of time to the wrapped time
|
264
292
|
def add(type, val)
|
265
293
|
type = :day if type == :wday
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
end
|
275
|
-
end
|
294
|
+
@time += case type
|
295
|
+
when :year then TimeUtil.days_in_n_years(@time, val) * ONE_DAY
|
296
|
+
when :month then TimeUtil.days_in_n_months(@time, val) * ONE_DAY
|
297
|
+
when :day then val * ONE_DAY
|
298
|
+
when :hour then val * ONE_HOUR
|
299
|
+
when :min then val * ONE_MINUTE
|
300
|
+
when :sec then val
|
301
|
+
end
|
276
302
|
end
|
277
303
|
|
278
304
|
# Clear everything below a certain type
|
@@ -281,23 +307,20 @@ module IceCube
|
|
281
307
|
type = :day if type == :wday
|
282
308
|
CLEAR_ORDER.each do |ptype|
|
283
309
|
break if ptype == type
|
284
|
-
|
285
|
-
send(:"clear_#{ptype}")
|
286
|
-
end
|
310
|
+
send :"clear_#{ptype}"
|
287
311
|
end
|
288
312
|
end
|
289
313
|
|
290
|
-
|
314
|
+
def hour=(value)
|
315
|
+
@time += (value * ONE_HOUR) - (@time.hour * ONE_HOUR)
|
316
|
+
end
|
291
317
|
|
292
|
-
def
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
else
|
299
|
-
yield
|
300
|
-
end
|
318
|
+
def min=(value)
|
319
|
+
@time += (value * ONE_MINUTE) - (@time.min * ONE_MINUTE)
|
320
|
+
end
|
321
|
+
|
322
|
+
def sec=(value)
|
323
|
+
@time += (value) - (@time.sec)
|
301
324
|
end
|
302
325
|
|
303
326
|
def clear_sec
|
@@ -326,10 +349,6 @@ module IceCube
|
|
326
349
|
@time += ONE_DAY
|
327
350
|
end
|
328
351
|
|
329
|
-
def clear_year
|
330
|
-
@time
|
331
|
-
end
|
332
|
-
|
333
352
|
end
|
334
353
|
|
335
354
|
end
|
@@ -1,18 +1,11 @@
|
|
1
|
+
require 'ice_cube/input_alignment'
|
2
|
+
|
1
3
|
module IceCube
|
2
4
|
|
3
5
|
class ValidatedRule < Rule
|
4
6
|
|
5
7
|
include Validations::ScheduleLock
|
6
8
|
|
7
|
-
include Validations::HourOfDay
|
8
|
-
include Validations::MinuteOfHour
|
9
|
-
include Validations::SecondOfMinute
|
10
|
-
include Validations::DayOfMonth
|
11
|
-
include Validations::DayOfWeek
|
12
|
-
include Validations::Day
|
13
|
-
include Validations::MonthOfYear
|
14
|
-
include Validations::DayOfYear
|
15
|
-
|
16
9
|
include Validations::Count
|
17
10
|
include Validations::Until
|
18
11
|
|
@@ -51,15 +44,14 @@ module IceCube
|
|
51
44
|
Array(@validations[base_interval_validation.type])
|
52
45
|
end
|
53
46
|
|
54
|
-
def base_interval_type
|
55
|
-
base_interval_validation.type
|
56
|
-
end
|
57
|
-
|
58
47
|
# Compute the next time after (or including) the specified time in respect
|
59
48
|
# to the given start time
|
60
49
|
def next_time(time, start_time, closing_time)
|
61
50
|
@time = time
|
62
|
-
@start_time
|
51
|
+
unless @start_time
|
52
|
+
@start_time = realign(time, start_time)
|
53
|
+
@time = @start_time if @time < @start_time
|
54
|
+
end
|
63
55
|
|
64
56
|
return nil unless find_acceptable_time_before(closing_time)
|
65
57
|
|
@@ -71,17 +63,13 @@ module IceCube
|
|
71
63
|
start_time
|
72
64
|
end
|
73
65
|
|
74
|
-
def
|
75
|
-
|
76
|
-
end
|
77
|
-
|
78
|
-
def dst_adjust?
|
79
|
-
@validations[:interval].any? &:dst_adjust?
|
66
|
+
def full_required?
|
67
|
+
!occurrence_count.nil?
|
80
68
|
end
|
81
69
|
|
82
70
|
def to_s
|
83
71
|
builder = StringBuilder.new
|
84
|
-
@validations.
|
72
|
+
@validations.each_value do |validations|
|
85
73
|
validations.each do |validation|
|
86
74
|
validation.build_s(builder)
|
87
75
|
end
|
@@ -91,7 +79,7 @@ module IceCube
|
|
91
79
|
|
92
80
|
def to_hash
|
93
81
|
builder = HashBuilder.new(self)
|
94
|
-
@validations.
|
82
|
+
@validations.each_value do |validations|
|
95
83
|
validations.each do |validation|
|
96
84
|
validation.build_hash(builder)
|
97
85
|
end
|
@@ -101,7 +89,7 @@ module IceCube
|
|
101
89
|
|
102
90
|
def to_ical
|
103
91
|
builder = IcalBuilder.new
|
104
|
-
@validations.
|
92
|
+
@validations.each_value do |validations|
|
105
93
|
validations.each do |validation|
|
106
94
|
validation.build_ical(builder)
|
107
95
|
end
|
@@ -134,7 +122,7 @@ module IceCube
|
|
134
122
|
|
135
123
|
def normalized_interval(interval)
|
136
124
|
int = interval.to_i
|
137
|
-
raise ArgumentError, "'#{interval}' is not a valid input for interval. Please pass
|
125
|
+
raise ArgumentError, "'#{interval}' is not a valid input for interval. Please pass a postive integer." unless int > 0
|
138
126
|
int
|
139
127
|
end
|
140
128
|
|
@@ -190,6 +178,12 @@ module IceCube
|
|
190
178
|
VALIDATION_ORDER & @validations.keys
|
191
179
|
end
|
192
180
|
|
181
|
+
def verify_alignment(value, freq, rule_part)
|
182
|
+
InputAlignment.new(self, value, rule_part).verify(freq) do |error|
|
183
|
+
yield error
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
193
187
|
end
|
194
188
|
|
195
189
|
end
|
@@ -4,14 +4,13 @@ module IceCube
|
|
4
4
|
|
5
5
|
# Value reader for limit
|
6
6
|
def occurrence_count
|
7
|
-
@count
|
7
|
+
(arr = @validations[:count]) && (val = arr[0]) && val.count
|
8
8
|
end
|
9
9
|
|
10
10
|
def count(max)
|
11
11
|
unless max.nil? || max.is_a?(Integer)
|
12
12
|
raise ArgumentError, "Expecting Integer or nil value for count, got #{max.inspect}"
|
13
13
|
end
|
14
|
-
@count = max
|
15
14
|
replace_validations_for(:count, max && [Validation.new(max, self)])
|
16
15
|
self
|
17
16
|
end
|
@@ -4,7 +4,11 @@ module IceCube
|
|
4
4
|
|
5
5
|
# Add a new interval validation
|
6
6
|
def interval(interval)
|
7
|
-
|
7
|
+
interval = normalized_interval(interval)
|
8
|
+
verify_alignment(interval, :wday, :interval) { |error| raise error }
|
9
|
+
verify_alignment(interval, :day, :interval) { |error| raise error }
|
10
|
+
|
11
|
+
@interval = interval
|
8
12
|
replace_validations_for(:interval, [Validation.new(@interval)])
|
9
13
|
clobber_base_validations(:wday, :day)
|
10
14
|
self
|
@@ -1,5 +1,3 @@
|
|
1
|
-
require 'date'
|
2
|
-
|
3
1
|
module IceCube
|
4
2
|
|
5
3
|
module Validations::Day
|
@@ -12,6 +10,8 @@ module IceCube
|
|
12
10
|
raise ArgumentError, "expecting Integer or Symbol value for day, got #{day.inspect}"
|
13
11
|
end
|
14
12
|
day = TimeUtil.sym_to_wday(day)
|
13
|
+
verify_alignment(day, :wday, :day) { |error| raise error }
|
14
|
+
|
15
15
|
validations_for(:day) << Validation.new(day)
|
16
16
|
end
|
17
17
|
clobber_base_validations(:wday, :day)
|
@@ -27,6 +27,10 @@ module IceCube
|
|
27
27
|
@day = day
|
28
28
|
end
|
29
29
|
|
30
|
+
def key
|
31
|
+
:day
|
32
|
+
end
|
33
|
+
|
30
34
|
def type
|
31
35
|
:wday
|
32
36
|
end
|
@@ -7,6 +7,7 @@ module IceCube
|
|
7
7
|
unless day.is_a?(Integer)
|
8
8
|
raise ArgumentError, "expecting Integer value for day, got #{day.inspect}"
|
9
9
|
end
|
10
|
+
verify_alignment(day, :day, :day_of_month) { |error| raise error }
|
10
11
|
validations_for(:day_of_month) << Validation.new(day)
|
11
12
|
end
|
12
13
|
clobber_base_validations(:day, :wday)
|
@@ -22,6 +23,10 @@ module IceCube
|
|
22
23
|
@day = day
|
23
24
|
end
|
24
25
|
|
26
|
+
def key
|
27
|
+
:day_of_month
|
28
|
+
end
|
29
|
+
|
25
30
|
def type
|
26
31
|
:day
|
27
32
|
end
|
@@ -8,12 +8,31 @@ module IceCube
|
|
8
8
|
unless hour.is_a?(Integer)
|
9
9
|
raise ArgumentError, "expecting Integer value for hour, got #{hour.inspect}"
|
10
10
|
end
|
11
|
+
|
12
|
+
verify_alignment(hour, :hour, :hour_of_day) { |error| raise error }
|
13
|
+
|
11
14
|
validations_for(:hour_of_day) << Validation.new(hour)
|
12
15
|
end
|
13
16
|
clobber_base_validations(:hour)
|
14
17
|
self
|
15
18
|
end
|
16
19
|
|
20
|
+
def realign(opening_time, start_time)
|
21
|
+
return super unless validations[:hour_of_day]
|
22
|
+
freq = base_interval_validation.interval
|
23
|
+
|
24
|
+
first_hour = Array(validations[:hour_of_day]).min_by(&:value)
|
25
|
+
time = TimeUtil::TimeWrapper.new(start_time, false)
|
26
|
+
if freq > 1 && base_interval_validation.type == :hour
|
27
|
+
offset = first_hour.validate(opening_time, start_time)
|
28
|
+
time.add(:hour, offset - freq)
|
29
|
+
else
|
30
|
+
time.hour = first_hour.value
|
31
|
+
end
|
32
|
+
|
33
|
+
super opening_time, time.to_time
|
34
|
+
end
|
35
|
+
|
17
36
|
class Validation < Validations::FixedValue
|
18
37
|
|
19
38
|
attr_reader :hour
|
@@ -23,6 +42,10 @@ module IceCube
|
|
23
42
|
@hour = hour
|
24
43
|
end
|
25
44
|
|
45
|
+
def key
|
46
|
+
:hour_of_day
|
47
|
+
end
|
48
|
+
|
26
49
|
def type
|
27
50
|
:hour
|
28
51
|
end
|
@@ -3,6 +3,8 @@ module IceCube
|
|
3
3
|
module Validations::HourlyInterval
|
4
4
|
|
5
5
|
def interval(interval)
|
6
|
+
verify_alignment(interval, :hour, :interval) { |error| raise error }
|
7
|
+
|
6
8
|
@interval = normalized_interval(interval)
|
7
9
|
replace_validations_for(:interval, [Validation.new(@interval)])
|
8
10
|
clobber_base_validations(:hour)
|
@@ -7,12 +7,24 @@ module IceCube
|
|
7
7
|
unless minute.is_a?(Integer)
|
8
8
|
raise ArgumentError, "expecting Integer value for minute, got #{minute.inspect}"
|
9
9
|
end
|
10
|
+
|
11
|
+
verify_alignment(minute, :min, :minute_of_hour) { |error| raise error }
|
12
|
+
|
10
13
|
validations_for(:minute_of_hour) << Validation.new(minute)
|
11
14
|
end
|
12
15
|
clobber_base_validations(:min)
|
13
16
|
self
|
14
17
|
end
|
15
18
|
|
19
|
+
def realign(opening_time, start_time)
|
20
|
+
return super unless validations[:minute_of_hour]
|
21
|
+
|
22
|
+
first_minute = validations[:minute_of_hour].min_by(&:value)
|
23
|
+
time = TimeUtil::TimeWrapper.new(start_time, false)
|
24
|
+
time.min = first_minute.value
|
25
|
+
super opening_time, time.to_time
|
26
|
+
end
|
27
|
+
|
16
28
|
class Validation < Validations::FixedValue
|
17
29
|
|
18
30
|
attr_reader :minute
|
@@ -22,6 +34,10 @@ module IceCube
|
|
22
34
|
@minute = minute
|
23
35
|
end
|
24
36
|
|
37
|
+
def key
|
38
|
+
:minute_of_hour
|
39
|
+
end
|
40
|
+
|
25
41
|
def type
|
26
42
|
:min
|
27
43
|
end
|
@@ -3,6 +3,8 @@ module IceCube
|
|
3
3
|
module Validations::MinutelyInterval
|
4
4
|
|
5
5
|
def interval(interval)
|
6
|
+
verify_alignment(interval, :min, :interval) { |error| raise error }
|
7
|
+
|
6
8
|
@interval = normalized_interval(interval)
|
7
9
|
replace_validations_for(:interval, [Validation.new(@interval)])
|
8
10
|
clobber_base_validations(:min)
|
@@ -8,6 +8,7 @@ module IceCube
|
|
8
8
|
raise ArgumentError, "expecting Integer or Symbol value for month, got #{month.inspect}"
|
9
9
|
end
|
10
10
|
month = TimeUtil.sym_to_month(month)
|
11
|
+
verify_alignment(month, :month, :month_of_year) { |error| raise error }
|
11
12
|
validations_for(:month_of_year) << Validation.new(month)
|
12
13
|
end
|
13
14
|
clobber_base_validations :month
|
@@ -23,6 +24,10 @@ module IceCube
|
|
23
24
|
@month = month
|
24
25
|
end
|
25
26
|
|
27
|
+
def key
|
28
|
+
:month_of_year
|
29
|
+
end
|
30
|
+
|
26
31
|
def type
|
27
32
|
:month
|
28
33
|
end
|
@@ -32,7 +37,7 @@ module IceCube
|
|
32
37
|
end
|
33
38
|
|
34
39
|
def build_s(builder)
|
35
|
-
builder.piece(:month_of_year) << IceCube::I18n.t("
|
40
|
+
builder.piece(:month_of_year) << IceCube::I18n.t("date.month_names")[month]
|
36
41
|
end
|
37
42
|
|
38
43
|
def build_hash(builder)
|
@@ -3,7 +3,10 @@ module IceCube
|
|
3
3
|
module Validations::MonthlyInterval
|
4
4
|
|
5
5
|
def interval(interval)
|
6
|
-
|
6
|
+
interval = normalized_interval(interval)
|
7
|
+
verify_alignment(interval, :month, :interval) { |error| raise error }
|
8
|
+
|
9
|
+
@interval = interval
|
7
10
|
replace_validations_for(:interval, [Validation.new(@interval)])
|
8
11
|
clobber_base_validations(:month)
|
9
12
|
self
|