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.
Files changed (47) hide show
  1. checksums.yaml +5 -5
  2. data/config/locales/de.yml +1 -1
  3. data/config/locales/en.yml +7 -46
  4. data/config/locales/es.yml +47 -83
  5. data/config/locales/fr.yml +2 -2
  6. data/config/locales/it.yml +179 -0
  7. data/config/locales/ja.yml +52 -29
  8. data/config/locales/nl.yml +133 -0
  9. data/config/locales/pt-BR.yml +178 -0
  10. data/config/locales/sv.yml +1 -1
  11. data/lib/ice_cube/i18n.rb +11 -12
  12. data/lib/ice_cube/input_alignment.rb +89 -0
  13. data/lib/ice_cube/null_i18n.rb +12 -6
  14. data/lib/ice_cube/occurrence.rb +25 -23
  15. data/lib/ice_cube/parsers/ical_parser.rb +8 -5
  16. data/lib/ice_cube/rule.rb +5 -13
  17. data/lib/ice_cube/rules/daily_rule.rb +9 -0
  18. data/lib/ice_cube/rules/hourly_rule.rb +9 -0
  19. data/lib/ice_cube/rules/minutely_rule.rb +9 -0
  20. data/lib/ice_cube/rules/monthly_rule.rb +9 -0
  21. data/lib/ice_cube/rules/secondly_rule.rb +9 -0
  22. data/lib/ice_cube/rules/weekly_rule.rb +30 -9
  23. data/lib/ice_cube/rules/yearly_rule.rb +9 -0
  24. data/lib/ice_cube/schedule.rb +30 -29
  25. data/lib/ice_cube/single_occurrence_rule.rb +4 -0
  26. data/lib/ice_cube/time_util.rb +65 -46
  27. data/lib/ice_cube/validated_rule.rb +18 -24
  28. data/lib/ice_cube/validations/count.rb +1 -2
  29. data/lib/ice_cube/validations/daily_interval.rb +5 -1
  30. data/lib/ice_cube/validations/day.rb +6 -2
  31. data/lib/ice_cube/validations/day_of_month.rb +5 -0
  32. data/lib/ice_cube/validations/day_of_week.rb +1 -1
  33. data/lib/ice_cube/validations/hour_of_day.rb +23 -0
  34. data/lib/ice_cube/validations/hourly_interval.rb +2 -0
  35. data/lib/ice_cube/validations/minute_of_hour.rb +16 -0
  36. data/lib/ice_cube/validations/minutely_interval.rb +2 -0
  37. data/lib/ice_cube/validations/month_of_year.rb +6 -1
  38. data/lib/ice_cube/validations/monthly_interval.rb +4 -1
  39. data/lib/ice_cube/validations/schedule_lock.rb +4 -0
  40. data/lib/ice_cube/validations/second_of_minute.rb +19 -3
  41. data/lib/ice_cube/validations/secondly_interval.rb +2 -0
  42. data/lib/ice_cube/validations/until.rb +1 -2
  43. data/lib/ice_cube/validations/weekly_interval.rb +0 -2
  44. data/lib/ice_cube/version.rb +1 -1
  45. data/lib/ice_cube.rb +1 -3
  46. data/spec/spec_helper.rb +32 -9
  47. metadata +10 -7
@@ -0,0 +1,178 @@
1
+ pt-BR:
2
+ ice_cube:
3
+ pieces_connector: ' / '
4
+ not: 'exceto %{target}'
5
+ not_on: 'exceto o dia %{target}'
6
+ date:
7
+ formats:
8
+ default: '%-d %B %Y'
9
+ month_names:
10
+ -
11
+ - Janeiro
12
+ - Fevereiro
13
+ - Março
14
+ - Abril
15
+ - Maio
16
+ - Junho
17
+ - Julho
18
+ - Agosto
19
+ - Setembro
20
+ - Outubro
21
+ - Novembro
22
+ - Dezembro
23
+ day_names:
24
+ - Domingo
25
+ - Segunda
26
+ - Terça
27
+ - Quarta
28
+ - Quinta
29
+ - Sexta
30
+ - Sábado
31
+ times:
32
+ other: '%{count} vezes'
33
+ one: '%{count} vez'
34
+ until: 'até %{date}'
35
+ days_of_week: '%{segments} %{day}'
36
+ days_of_month:
37
+ other: '%{segments} dias do mês'
38
+ one: '%{segments} dia'
39
+ days_of_year:
40
+ other: '%{segments} dias do ano'
41
+ one: '%{segments} dia'
42
+ at_hours_of_the_day:
43
+ other: às %{segments} horas
44
+ one: à %{segments} hora
45
+ on_minutes_of_hour:
46
+ other: aos %{segments} minutos
47
+ one: ao %{segments} minuto
48
+ at_seconds_of_minute:
49
+ other: aos %{segments} segundos
50
+ one: ao %{segments} segundo
51
+ on_seconds_of_minute:
52
+ other: aos %{segments} segundos
53
+ one: ao %{segments} segundo
54
+ each_second:
55
+ one: A cada segundo
56
+ other: A cada %{count} segundos
57
+ each_minute:
58
+ one: A cada minuto
59
+ other: A cada %{count} minutos
60
+ each_hour:
61
+ one: A cada hora
62
+ other: A cada %{count} horas
63
+ each_day:
64
+ one: Diariamente
65
+ other: A cada %{count} dias
66
+ each_week:
67
+ one: Semanalmente
68
+ other: A cada %{count} semanas
69
+ each_month:
70
+ one: Mensalmente
71
+ other: A cada %{count} meses
72
+ each_year:
73
+ one: Anualmente
74
+ other: A cada %{count} anos
75
+ 'on': no %{sentence}
76
+ in: 'em %{target}'
77
+ integer:
78
+ negative: '%{ordinal} depois que acabar'
79
+ literal_ordinals:
80
+ -1: último
81
+ -2: penúltimo
82
+ ordinal: '%{number}%{ordinal}'
83
+ ordinals:
84
+ default: º
85
+ 1: º
86
+ 2: º
87
+ 3: º
88
+ 11: º
89
+ 12: º
90
+ 13: º
91
+ on_weekends: nos finais de semana
92
+ on_weekdays: nos dias úteis
93
+ days_on:
94
+ - Domingos
95
+ - Segundas-feiras
96
+ - Terças-feiras
97
+ - Quartas-feiras
98
+ - Quintas-feiras
99
+ - Sextas-feiras
100
+ - Sábados
101
+ on_days: no dia %{days}
102
+ array:
103
+ last_word_connector: ' e '
104
+ two_words_connector: ' e '
105
+ words_connector: ', '
106
+ string:
107
+ format:
108
+ day: '%{rest} %{current}'
109
+ day_of_week: '%{rest} %{current}'
110
+ day_of_month: '%{rest} %{current}'
111
+ day_of_year: '%{rest} %{current}'
112
+ hour_of_day: '%{rest} %{current}'
113
+ minute_of_hour: '%{rest} %{current}'
114
+ until: '%{rest} %{current}'
115
+ count: '%{rest} %{current}'
116
+ default: '%{rest} %{current}'
117
+
118
+ date:
119
+ abbr_day_names:
120
+ - Dom
121
+ - Seg
122
+ - Ter
123
+ - Qua
124
+ - Qui
125
+ - Sex
126
+ - Sáb
127
+ abbr_month_names:
128
+ -
129
+ - Jan
130
+ - Fev
131
+ - Mar
132
+ - Abr
133
+ - Mai
134
+ - Jun
135
+ - Jul
136
+ - Ago
137
+ - Set
138
+ - Out
139
+ - Nov
140
+ - Dez
141
+ day_names:
142
+ - Domingo
143
+ - Segunda-feira
144
+ - Terça-feira
145
+ - Quarta-feira
146
+ - Quinta-feira
147
+ - Sexta-feira
148
+ - Sábado
149
+ formats:
150
+ default: "%d/%m/%Y"
151
+ long: "%d de %B de %Y"
152
+ short: "%d de %B"
153
+ month_names:
154
+ -
155
+ - Janeiro
156
+ - Fevereiro
157
+ - Março
158
+ - Abril
159
+ - Maio
160
+ - Junho
161
+ - Julho
162
+ - Agosto
163
+ - Setembro
164
+ - Outubro
165
+ - Novembro
166
+ - Dezembro
167
+ order:
168
+ - :day
169
+ - :month
170
+ - :year
171
+
172
+ time:
173
+ am: ''
174
+ formats:
175
+ default: "%a, %d de %B de %Y, %H:%M:%S %z"
176
+ long: "%d de %B de %Y, %H:%M"
177
+ short: "%d de %B, %H:%M"
178
+ pm: ''
@@ -127,7 +127,7 @@ sv:
127
127
  - Aug
128
128
  - Sep
129
129
  - Okt
130
- - Mov
130
+ - Nov
131
131
  - Dec
132
132
  day_names:
133
133
  - Söndag
data/lib/ice_cube/i18n.rb CHANGED
@@ -1,24 +1,23 @@
1
+ require 'ice_cube/null_i18n'
2
+
1
3
  module IceCube
2
4
  module I18n
3
- def self.t(*args)
4
- backend.t(*args)
5
- end
6
5
 
7
- def self.l(*args)
8
- backend.l(*args)
6
+ LOCALES_PATH = File.expand_path(File.join('..', '..', '..', 'config', 'locales'), __FILE__)
7
+
8
+ class << self
9
+ delegate :t, :l, to: :backend
9
10
  end
10
11
 
11
12
  def self.backend
12
- @backend
13
+ @backend ||= detect_backend!
13
14
  end
14
15
 
15
16
  def self.detect_backend!
16
- require 'i18n'
17
- ::I18n.load_path += Dir[File.expand_path('../../../config/locales/*{rb,yml}', __FILE__)]
18
- @backend = ::I18n
19
- rescue LoadError
20
- require 'ice_cube/null_i18n'
21
- @backend = NullI18n
17
+ ::I18n.load_path += Dir[File.join(LOCALES_PATH, '*.yml')]
18
+ ::I18n
19
+ rescue NameError
20
+ NullI18n
22
21
  end
23
22
  end
24
23
  end
@@ -0,0 +1,89 @@
1
+ module IceCube
2
+ class InputAlignment
3
+
4
+ def initialize(rule, value, rule_part)
5
+ @rule = rule
6
+ @value = value
7
+ @rule_part = rule_part
8
+ end
9
+
10
+ attr_reader :rule, :value, :rule_part
11
+
12
+ def verify(freq, options={}, &block)
13
+ @rule.validations[:interval] or return
14
+
15
+ case @rule
16
+ when DailyRule
17
+ verify_wday_alignment(freq, &block)
18
+ when MonthlyRule
19
+ verify_month_alignment(freq, &block)
20
+ else
21
+ verify_freq_alignment(freq, &block)
22
+ end
23
+ end
24
+
25
+ private
26
+
27
+ def interval_validation
28
+ @interval_validation ||= @rule.validations[:interval].first
29
+ end
30
+
31
+ def interval_value
32
+ @interval_value ||= (rule_part == :interval) ? value : interval_validation.interval
33
+ end
34
+
35
+ def fixed_validations
36
+ @fixed_validations ||= @rule.validations.values.flatten.select { |v|
37
+ interval_type = (v.type == :wday ? :day : v.type)
38
+ v.class < Validations::FixedValue &&
39
+ interval_type == rule.base_interval_validation.type
40
+ }
41
+ end
42
+
43
+ def verify_freq_alignment(freq)
44
+ interval_validation.type == freq or return
45
+ (last_validation = fixed_validations.min_by(&:value)) or return
46
+
47
+ alignment = (value - last_validation.value) % interval_validation.interval
48
+ return if alignment.zero?
49
+
50
+ validation_values = fixed_validations.map(&:value).join(', ')
51
+ if rule_part == :interval
52
+ message = "interval(#{value}) " \
53
+ "must be a multiple of " \
54
+ "intervals in #{last_validation.key}(#{validation_values})"
55
+ else
56
+ message = "intervals in #{last_validation.key}(#{validation_values}, #{value}) " \
57
+ "must be multiples of " \
58
+ "interval(#{interval_validation.interval})"
59
+ end
60
+
61
+ yield ArgumentError.new(message)
62
+ end
63
+
64
+ def verify_month_alignment(_freq)
65
+ return if interval_value == 1 || (interval_value % 12).zero?
66
+ return if fixed_validations.empty?
67
+
68
+ message = "month_of_year can only be used with interval(1) or multiples of interval(12)"
69
+
70
+ yield ArgumentError.new(message)
71
+ end
72
+
73
+ def verify_wday_alignment(freq)
74
+ return if interval_value == 1
75
+
76
+ if freq == :wday
77
+ return if (interval_value % 7).zero?
78
+ return if Array(@rule.validations[:day]).empty?
79
+ message = "day can only be used with multiples of interval(7)"
80
+ else
81
+ (fixed_validation = fixed_validations.first) or return
82
+ message = "#{fixed_validation.key} can only be used with interval(1)"
83
+ end
84
+
85
+ yield ArgumentError.new(message)
86
+ end
87
+
88
+ end
89
+ end
@@ -7,13 +7,19 @@ module IceCube
7
7
 
8
8
  base = base[options[:count] == 1 ? "one" : "other"] if options[:count]
9
9
 
10
- if base.is_a?(Hash)
11
- return base.each_with_object({}) do |(key, value), hash|
12
- hash[key.is_a?(String) ? key.to_sym : key] = value
10
+ case base
11
+ when Hash
12
+ base.each_with_object({}) do |(k, v), hash|
13
+ hash[k.is_a?(String) ? k.to_sym : k] = v
13
14
  end
15
+ when Array
16
+ base.each_with_index.each_with_object({}) do |(v, k), hash|
17
+ hash[k] = v
18
+ end
19
+ else
20
+ return base unless base.include?('%{')
21
+ base % options
14
22
  end
15
-
16
- options.reduce(base) { |result, (find, replace)| result.gsub("%{#{find}}", "#{replace}") }
17
23
  end
18
24
 
19
25
  def self.l(date_or_time, options = {})
@@ -22,7 +28,7 @@ module IceCube
22
28
  end
23
29
 
24
30
  def self.config
25
- @config ||= YAML.load(File.read(File.join(File.dirname(__FILE__), '..', '..', 'config', 'locales', 'en.yml')))['en']
31
+ @config ||= YAML.load_file(File.join(IceCube::I18n::LOCALES_PATH, 'en.yml'))['en']
26
32
  end
27
33
  end
28
34
  end
@@ -1,4 +1,3 @@
1
- require 'forwardable'
2
1
  require 'delegate'
3
2
 
4
3
  module IceCube
@@ -20,18 +19,16 @@ module IceCube
20
19
  # Time.now - Occurrence.new(start_time) # => 3600
21
20
  #
22
21
  class Occurrence < SimpleDelegator
22
+ include Comparable
23
23
 
24
24
  # Report class name as 'Time' to thwart type checking.
25
25
  def self.name
26
26
  'Time'
27
27
  end
28
28
 
29
- # Optimize for common methods to avoid method_missing
30
- extend Forwardable
31
- def_delegators :start_time, :to_i, :<=>, :==
32
- def_delegators :to_range, :cover?, :include?, :each, :first, :last
33
-
34
29
  attr_reader :start_time, :end_time
30
+ alias first start_time
31
+ alias last end_time
35
32
 
36
33
  def initialize(start_time, end_time=nil)
37
34
  @start_time = start_time
@@ -39,29 +36,34 @@ module IceCube
39
36
  __setobj__ @start_time
40
37
  end
41
38
 
39
+ def to_i
40
+ @start_time.to_i
41
+ end
42
+
43
+ def <=>(other)
44
+ @start_time <=> other
45
+ end
46
+
42
47
  def is_a?(klass)
43
48
  klass == ::Time || super
44
49
  end
45
50
  alias_method :kind_of?, :is_a?
46
51
 
47
- def intersects? other
48
- if other.is_a?(Occurrence) || other.is_a?(Range)
49
- lower_bound_1 = first + 1
50
- upper_bound_1 = last # exclude end
51
- lower_bound_2 = other.first + 1
52
- upper_bound_2 = other.last + 1
53
- if (lower_bound_2 <=> upper_bound_2) > 0
54
- false
55
- elsif (lower_bound_1 <=> upper_bound_1) > 0
56
- false
57
- else
58
- (upper_bound_1 <=> lower_bound_2) >= 0 and
59
- (upper_bound_2 <=> lower_bound_1) >= 0
60
- end
61
- else
62
- cover? other
63
- end
52
+ def intersects?(other)
53
+ return cover?(other) unless other.is_a?(Occurrence) || other.is_a?(Range)
54
+
55
+ this_start = first + 1
56
+ this_end = last # exclude end boundary
57
+ other_start = other.first + 1
58
+ other_end = other.last + 1
59
+
60
+ !(this_end < other_start || this_start > other_end)
61
+ end
62
+
63
+ def cover?(other)
64
+ to_range.cover?(other)
64
65
  end
66
+ alias_method :include?, :cover?
65
67
 
66
68
  def comparable_time
67
69
  start_time
@@ -4,15 +4,18 @@ module IceCube
4
4
  data = {}
5
5
  ical_string.each_line do |line|
6
6
  (property, value) = line.split(':')
7
- (property, tzid) = property.split(';')
7
+ (property, _tzid) = property.split(';')
8
8
  case property
9
9
  when 'DTSTART'
10
- data[:start_time] = Time.parse(value)
10
+ data[:start_time] = TimeUtil.deserialize_time(value)
11
11
  when 'DTEND'
12
- data[:end_time] = Time.parse(value)
12
+ data[:end_time] = TimeUtil.deserialize_time(value)
13
+ when 'RDATE'
14
+ data[:rtimes] ||= []
15
+ data[:rtimes] += value.split(',').map { |v| TimeUtil.deserialize_time(v) }
13
16
  when 'EXDATE'
14
17
  data[:extimes] ||= []
15
- data[:extimes] += value.split(',').map{|v| Time.parse(v)}
18
+ data[:extimes] += value.split(',').map { |v| TimeUtil.deserialize_time(v) }
16
19
  when 'DURATION'
17
20
  data[:duration] # FIXME
18
21
  when 'RRULE'
@@ -41,7 +44,7 @@ module IceCube
41
44
  when 'COUNT'
42
45
  params[:count] = value.to_i
43
46
  when 'UNTIL'
44
- params[:until] = Time.parse(value).utc
47
+ params[:until] = TimeUtil.deserialize_time(value).utc
45
48
  when 'WKST'
46
49
  params[:week_start] = TimeUtil.ical_day_to_symbol(value)
47
50
  when 'BYSECOND'
data/lib/ice_cube/rule.rb CHANGED
@@ -19,20 +19,17 @@ module IceCube
19
19
  until_time || occurrence_count
20
20
  end
21
21
 
22
- def ==(rule)
23
- if rule.is_a? Rule
24
- hash = to_hash
25
- hash && hash == rule.to_hash
26
- end
22
+ def ==(other)
23
+ return false unless other.is_a? Rule
24
+ hash == other.hash
27
25
  end
28
26
 
29
27
  def hash
30
- h = to_hash
31
- h.nil? ? super : h.hash
28
+ to_hash.hash
32
29
  end
33
30
 
34
31
  def to_ical
35
- raise MethodNotImplemented, "Expected to be overrridden by subclasses"
32
+ raise MethodNotImplemented, "Expected to be overridden by subclasses"
36
33
  end
37
34
 
38
35
  # Convert from ical string and create a rule
@@ -61,11 +58,6 @@ module IceCube
61
58
  next_time(time, schedule, time).to_i == time.to_i
62
59
  end
63
60
 
64
- # Whether this rule requires a full run
65
- def full_required?
66
- !@count.nil?
67
- end
68
-
69
61
  class << self
70
62
 
71
63
  # Convert from a hash and create a rule
@@ -2,6 +2,15 @@ module IceCube
2
2
 
3
3
  class DailyRule < ValidatedRule
4
4
 
5
+ include Validations::HourOfDay
6
+ include Validations::MinuteOfHour
7
+ include Validations::SecondOfMinute
8
+ include Validations::DayOfMonth
9
+ include Validations::DayOfWeek
10
+ include Validations::Day
11
+ include Validations::MonthOfYear
12
+ # include Validations::DayOfYear # n/a
13
+
5
14
  include Validations::DailyInterval
6
15
 
7
16
  def initialize(interval = 1)
@@ -2,6 +2,15 @@ module IceCube
2
2
 
3
3
  class HourlyRule < ValidatedRule
4
4
 
5
+ include Validations::HourOfDay
6
+ include Validations::MinuteOfHour
7
+ include Validations::SecondOfMinute
8
+ include Validations::DayOfMonth
9
+ include Validations::DayOfWeek
10
+ include Validations::Day
11
+ include Validations::MonthOfYear
12
+ include Validations::DayOfYear
13
+
5
14
  include Validations::HourlyInterval
6
15
 
7
16
  def initialize(interval = 1)
@@ -2,6 +2,15 @@ module IceCube
2
2
 
3
3
  class MinutelyRule < ValidatedRule
4
4
 
5
+ include Validations::HourOfDay
6
+ include Validations::MinuteOfHour
7
+ include Validations::SecondOfMinute
8
+ include Validations::DayOfMonth
9
+ include Validations::DayOfWeek
10
+ include Validations::Day
11
+ include Validations::MonthOfYear
12
+ include Validations::DayOfYear
13
+
5
14
  include Validations::MinutelyInterval
6
15
 
7
16
  def initialize(interval = 1)
@@ -2,6 +2,15 @@ module IceCube
2
2
 
3
3
  class MonthlyRule < ValidatedRule
4
4
 
5
+ include Validations::HourOfDay
6
+ include Validations::MinuteOfHour
7
+ include Validations::SecondOfMinute
8
+ include Validations::DayOfMonth
9
+ include Validations::DayOfWeek
10
+ include Validations::Day
11
+ include Validations::MonthOfYear
12
+ # include Validations::DayOfYear # n/a
13
+
5
14
  include Validations::MonthlyInterval
6
15
 
7
16
  def initialize(interval = 1)
@@ -2,6 +2,15 @@ module IceCube
2
2
 
3
3
  class SecondlyRule < ValidatedRule
4
4
 
5
+ include Validations::HourOfDay
6
+ include Validations::MinuteOfHour
7
+ include Validations::SecondOfMinute
8
+ include Validations::DayOfMonth
9
+ include Validations::DayOfWeek
10
+ include Validations::Day
11
+ include Validations::MonthOfYear
12
+ include Validations::DayOfYear
13
+
5
14
  include Validations::SecondlyInterval
6
15
 
7
16
  def initialize(interval = 1)
@@ -2,6 +2,15 @@ module IceCube
2
2
 
3
3
  class WeeklyRule < ValidatedRule
4
4
 
5
+ include Validations::HourOfDay
6
+ include Validations::MinuteOfHour
7
+ include Validations::SecondOfMinute
8
+ # include Validations::DayOfMonth # n/a
9
+ include Validations::DayOfWeek
10
+ include Validations::Day
11
+ include Validations::MonthOfYear
12
+ # include Validations::DayOfYear # n/a
13
+
5
14
  include Validations::WeeklyInterval
6
15
 
7
16
  attr_reader :week_start
@@ -13,25 +22,37 @@ module IceCube
13
22
  reset
14
23
  end
15
24
 
16
- # Calculate the effective start time for when the given start time is later
17
- # in the week than one of the weekday validations, such that times could be
18
- # missed by a 7-day jump using the weekly interval, or when selecting from a
19
- # date that is misaligned from the schedule interval.
25
+ # Move the effective start time to correct for when the schedule has
26
+ # validations earlier in the week than the selected start time, e.g.
27
+ #
28
+ # Schedule.new(wednesday).weekly(2).day(:monday)
29
+ #
30
+ # The effective start time gets realigned to the second next Monday, jumping
31
+ # over the gap week for the interval (2). Without realignment, the correct
32
+ # Monday occurrence would be missed when the schedule performs a 7-day jump
33
+ # into the next interval week, arriving on the Wednesday. This corrects any
34
+ # selections from dates that are misaligned to the schedule interval.
20
35
  #
21
36
  def realign(step_time, start_time)
22
37
  time = TimeUtil::TimeWrapper.new(start_time)
23
38
  offset = wday_offset(step_time, start_time)
24
- time.add(:day, offset) if offset
25
- time.to_time
39
+ time.add(:day, offset)
40
+ super step_time, time.to_time
26
41
  end
27
42
 
43
+ # Calculate how many days to the first wday validation in the correct
44
+ # interval week. This may move backwards within the week if starting in an
45
+ # interval week with earlier validations.
46
+ #
28
47
  def wday_offset(step_time, start_time)
48
+ return 0 if step_time == start_time
49
+
29
50
  wday_validations = other_interval_validations.select { |v| v.type == :wday }
30
- return if wday_validations.none?
51
+ return 0 if wday_validations.none?
31
52
 
32
- days = (step_time - start_time).to_i / ONE_DAY
53
+ days = step_time.to_date - start_time.to_date
33
54
  interval = base_interval_validation.validate(step_time, start_time).to_i
34
- min_wday = TimeUtil.normalize_wday(wday_validations.min_by(&:day).day, week_start)
55
+ min_wday = wday_validations.map { |v| TimeUtil.normalize_wday(v.day, week_start) }.min
35
56
  step_wday = TimeUtil.normalize_wday(step_time.wday, week_start)
36
57
 
37
58
  days + interval - step_wday + min_wday
@@ -2,6 +2,15 @@ module IceCube
2
2
 
3
3
  class YearlyRule < ValidatedRule
4
4
 
5
+ include Validations::HourOfDay
6
+ include Validations::MinuteOfHour
7
+ include Validations::SecondOfMinute
8
+ include Validations::DayOfMonth
9
+ include Validations::DayOfWeek
10
+ include Validations::Day
11
+ include Validations::MonthOfYear
12
+ include Validations::DayOfYear
13
+
5
14
  include Validations::YearlyInterval
6
15
 
7
16
  def initialize(interval = 1)