ice_cube 0.16.0 → 0.16.4
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.
- 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
|