opening_hours_converter 1.8.1 → 1.9.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8182729b4890b6c79b8173b5ed0722da103a4f82820ff62119d63f2d0ca2de72
4
- data.tar.gz: bbbab689b9eddebb5dd17e715a15c940dd62cd0fa58b06b860c1234544c2bdf7
3
+ metadata.gz: 0421f6038fb3bcaae15b1e29d5a4bb90b08d829e4bd68d2d4c3501307fa8b8c7
4
+ data.tar.gz: '059ed79dab312bfa859028e9ec420ff99ae0e718a8723b98e61622fea8f85ae6'
5
5
  SHA512:
6
- metadata.gz: 241b74370dd846929cccb2fdde19960689d05ce6a7a31c863ea331b6450ce57ba0a88042abb2ecbc588cf38229356e82f43a3d16496513311445aa2787ff40e9
7
- data.tar.gz: 528266324133acf97320be51b0f8f4f2b3e99907e2ff3a0c620b5d7e41cfa3339bb7d00bfeb3d915111fbfaa7a966100f20ee723f56ada32d0adf40572d67f0b
6
+ metadata.gz: 9319c1fc314fe58bbad62abf9e59c3525069f7324189dda6f938dad328869cd6a5b63ba65ab6965b3e3286e8bce782777d4be88bbac541a87daba0568071e0cb
7
+ data.tar.gz: 26304defc99f58cceab36cf8bf0ae773651c2ab641b490601d1ff8b60446441af3c52234016e2a19ea73e1648ae05f014087eef9a8dcf5ce8ab1b16dcb5eea22
@@ -1,6 +1,11 @@
1
1
  module OpeningHoursConverter
2
2
  require 'date'
3
+ require 'pry'
4
+ require_relative './opening_hours_converter/utils'
3
5
  require_relative './opening_hours_converter/date_range'
6
+ require_relative './opening_hours_converter/token'
7
+ require_relative './opening_hours_converter/tokenizer'
8
+ require_relative './opening_hours_converter/tokens_handler'
4
9
  require_relative './opening_hours_converter/day'
5
10
  require_relative './opening_hours_converter/week'
6
11
  require_relative './opening_hours_converter/year'
@@ -13,4 +18,5 @@ module OpeningHoursConverter
13
18
  require_relative './opening_hours_converter/opening_hours_rule'
14
19
  require_relative './opening_hours_converter/opening_hours_time'
15
20
  require_relative './opening_hours_converter/wide_interval'
21
+ require_relative './opening_hours_converter/week_index'
16
22
  end
@@ -3,6 +3,7 @@ require 'opening_hours_converter/constants'
3
3
  module OpeningHoursConverter
4
4
  class Iterator
5
5
  include Constants
6
+ include Utils
6
7
 
7
8
  def get_iterator(date_ranges)
8
9
  date_ranges_array = []
@@ -78,7 +79,7 @@ module OpeningHoursConverter
78
79
  end
79
80
  date_ranges[index].typical.intervals.each do |i|
80
81
  next unless !i.nil? && !i.is_off
81
- next unless (i.day_start..i.day_end).cover?(fix_datetime_wday(day.wday)) || (is_ph && year_ph.include?(Time.new(day.year, day.month, day.day)))
82
+ next unless (i.day_start..i.day_end).cover?(reindex_sunday_week_to_monday_week(day.wday)) || (is_ph && year_ph.include?(Time.new(day.year, day.month, day.day)))
82
83
  itr = { start: Time.new(day.year, day.month, day.day, i.start / 60, i.start % 60),
83
84
  end: Time.new(day.year, day.month, day.day, i.end / 60, i.end % 60) }
84
85
  datetime_result << itr unless datetime_result.include?(itr)
@@ -98,7 +99,7 @@ module OpeningHoursConverter
98
99
  result.each do |interval|
99
100
  (interval[:start]..interval[:end]).each do |day|
100
101
  date_ranges[index].typical.intervals.each do |i|
101
- if (i.day_start..i.day_end).cover?(fix_datetime_wday(day.wday))
102
+ if (i.day_start..i.day_end).cover?(reindex_sunday_week_to_monday_week(day.wday))
102
103
  datetime_result << { start: DateTime.new(day.year, day.month, day.day, i.start / 60, i.start % 60),
103
104
  end: DateTime.new(day.year, day.month, day.day, i.end / 60, i.end % 60) }
104
105
  end
@@ -110,10 +111,6 @@ module OpeningHoursConverter
110
111
  datetime_result.sort_by { |a| a[:start] }
111
112
  end
112
113
 
113
- def fix_datetime_wday(d)
114
- d == 0 ? 6 : d - 1
115
- end
116
-
117
114
  # A partir d'une string OH et d'une DateTime (= now par défaut), renvoyer le current state (début / fin / commentaire)
118
115
  def state(opening_hours_string, time = Time.now)
119
116
  date_ranges = OpeningHoursConverter::OpeningHoursParser.new.parse(opening_hours_string)
@@ -154,13 +151,5 @@ module OpeningHoursConverter
154
151
  end
155
152
  false
156
153
  end
157
-
158
- def datetime_to_time(datetime)
159
- Time.new(datetime.year, datetime.month, datetime.day, datetime.hour, datetime.min, datetime.sec, datetime.zone)
160
- end
161
-
162
- def time_to_datetime(time)
163
- DateTime.new(time.year, time.month, time.day, time.hour, time.min, time.sec, Rational(time.gmt_offset / 3600, 24))
164
- end
165
154
  end
166
155
  end
@@ -10,21 +10,25 @@ module OpeningHoursConverter
10
10
  oh_rule_added = nil
11
11
  range_general = nil
12
12
  range_general_for = nil
13
- day_ph = false
14
- off_day_ph = false
15
13
 
16
14
  date_ranges.each_with_index do |date_range, date_range_index|
17
15
  next unless !date_range.nil?
18
- if date_range.typical.intervals.length != 1
19
- date_range.typical.intervals.each_with_index do |interval, interval_id|
20
- next unless interval&.day_start == -2 && interval&.day_start == interval&.day_end
21
- if interval.is_off
22
- off_day_ph = true
23
- else
24
- day_ph = true
25
- end
26
- date_range.typical.remove_interval(interval_id)
16
+
17
+ day_ph = false
18
+ off_day_ph = false
19
+ phs = []
20
+
21
+ date_range.typical.intervals.each_with_index do |interval, interval_id|
22
+ next unless interval&.day_start == -2 && interval&.day_start == interval&.day_end
23
+
24
+ if interval.is_off
25
+ off_day_ph = true
26
+ else
27
+ day_ph = true
27
28
  end
29
+
30
+ phs << interval
31
+ date_range.typical.remove_interval(interval_id)
28
32
  end
29
33
 
30
34
  range_general = nil
@@ -44,9 +48,7 @@ module OpeningHoursConverter
44
48
  end
45
49
 
46
50
  next unless date_range_index == 0 || range_general.nil?
47
- if date_range.typical&.intervals&.length == 1 && date_range.typical&.intervals[0].day_start == -2 && date_range.typical&.intervals[0].day_end == -2
48
- oh_rules = build_holiday(date_range)
49
- elsif date_range.defines_typical_week?
51
+ if date_range.defines_typical_week?
50
52
  oh_rules = if !range_general_for.nil?
51
53
  build_week_diff(date_range, date_ranges[range_general_for])
52
54
  else
@@ -72,7 +74,6 @@ module OpeningHoursConverter
72
74
  end
73
75
  oh_rule_added = true
74
76
  rescue Exception => e
75
- puts e
76
77
  if oh_rule.date[0].wide_interval.type == 'holiday' && oh_rule.date[0].wide_interval.get_time_selector == 'PH'
77
78
  rules[rule_index].add_ph_weekday
78
79
  oh_rule_added = true
@@ -89,12 +90,38 @@ module OpeningHoursConverter
89
90
  end
90
91
  end
91
92
 
92
- oh_rule.add_ph_weekday if day_ph
93
+ if off_day_ph || day_ph
94
+ if date_range.typical.intervals.uniq == [nil]
95
+ oh_rule.date.first.weekdays = [-2]
96
+ if off_day_ph
97
+ oh_rule.is_defined_off = off_day_ph
98
+ phs = []
99
+ else
100
+ phs.reverse.each do |interval|
101
+ oh_rule.add_time(OpeningHoursConverter::OpeningHoursTime.new(interval.start, interval.end))
102
+ end
103
+ end
104
+ else
105
+ if times_are_compatible?(oh_rule, phs)
106
+ holiday_intervals = get_compatible_intervals(oh_rule, phs)
107
+ oh_rule.add_ph_weekday if holiday_intervals[:compatible].length > 0
108
+ rules << oh_rule if !oh_rule_added
109
+ oh_rule_added = true
110
+ holiday_intervals[:incompatible].each do |interval|
111
+ rules += build_off_holiday(date_range) if off_day_ph
112
+ rules += build_holiday(date_range) if day_ph
113
+ end
114
+ else
115
+ rules << oh_rule if !oh_rule_added
116
+ oh_rule_added = true
117
+ rules += build_off_holiday(date_range) if off_day_ph
118
+ rules += build_holiday(date_range) if day_ph
119
+ end
120
+ end
121
+ end
93
122
 
94
123
  rules << oh_rule if !oh_rule_added
95
124
 
96
- rules += build_off_holiday(date_range) if off_day_ph
97
-
98
125
  next unless oh_rule == oh_rules.last && oh_rule.has_overwritten_weekday?
99
126
  oh_rule_over = OpeningHoursConverter::OpeningHoursRule.new
100
127
 
@@ -118,6 +145,34 @@ module OpeningHoursConverter
118
145
  result.strip
119
146
  end
120
147
 
148
+ def times_are_compatible?(oh_rule, phs)
149
+ if oh_rule.is_defined_off
150
+ phs.any?(&:is_off)
151
+ else
152
+ phs.any? do |ph_interval|
153
+ oh_rule.time.any? do |rule_time|
154
+ rule_time.start == ph_interval.start && rule_time.end == ph_interval.end
155
+ end
156
+ end
157
+ end
158
+ end
159
+
160
+ def get_compatible_intervals(oh_rule, phs)
161
+ compatibility = {
162
+ compatible: [],
163
+ incompatible: []
164
+ }
165
+
166
+ compatibility[:compatible] = phs.select do |ph_interval|
167
+ return false if ph_interval.is_off != oh_rule.is_defined_off
168
+
169
+ oh_rule.time.any? { |rule_time| rule_time.start == ph_interval.start && rule_time.end == ph_interval.end }
170
+ end
171
+ compatibility[:incompatible] = phs - compatibility[:compatible]
172
+
173
+ compatibility
174
+ end
175
+
121
176
  def build_off_holiday(date_range)
122
177
  start_year = date_range.wide_interval.start&.key?(:year) ? date_range.wide_interval.start[:year] : date_range.wide_interval.start
123
178
  end_year = date_range.wide_interval.end&.key?(:year) ? date_range.wide_interval.end[:year] : date_range.wide_interval.end
@@ -135,9 +190,15 @@ module OpeningHoursConverter
135
190
  def build_holiday(date_range)
136
191
  start_year = date_range.wide_interval.start&.key?(:year) ? date_range.wide_interval.start[:year] : date_range.wide_interval.start
137
192
  end_year = date_range.wide_interval.end&.key?(:year) ? date_range.wide_interval.end[:year] : date_range.wide_interval.end
138
-
139
193
  intervals = date_range.typical.get_intervals(true)
140
- date_range = OpeningHoursConverter::DateRange.new(OpeningHoursConverter::WideInterval.new.holiday('PH', start_year, end_year))
194
+
195
+ if date_range.wide_interval.type == 'week'
196
+ intervals.each do |interval|
197
+ date_range.typical.add_interval(OpeningHoursConverter::Interval.new(-2, interval.start, -2, interval.end, interval.is_off))
198
+ end
199
+ else
200
+ date_range = OpeningHoursConverter::DateRange.new(OpeningHoursConverter::WideInterval.new.holiday('PH', start_year, end_year))
201
+ end
141
202
 
142
203
  for i in 0..6
143
204
  intervals.each do |interval|
@@ -156,7 +217,6 @@ module OpeningHoursConverter
156
217
  rule.is_defined_off = rule.is_defined_off || interval.is_off
157
218
  end
158
219
  end
159
-
160
220
  [rule]
161
221
  end
162
222
 
@@ -327,6 +387,7 @@ module OpeningHoursConverter
327
387
 
328
388
  def create_time_intervals(wide_interval, intervals)
329
389
  days = []
390
+
330
391
  for i in 0...7
331
392
  days << OpeningHoursConverter::OpeningHoursRule.new
332
393
  days[i].add_date(OpeningHoursConverter::OpeningHoursDate.new(wide_interval, [i]))
@@ -109,7 +109,7 @@ module OpeningHoursConverter
109
109
  end
110
110
 
111
111
  def add_overwritten_weekday(weekday)
112
- return if @weekdays_over.include?(weekday) && @weekdays_over.include?(weekday)
112
+ return if @weekdays_over.include?(weekday)
113
113
 
114
114
  @weekdays_over << weekday
115
115
  @weekdays_over.sort!
@@ -1,23 +1,31 @@
1
1
  require 'opening_hours_converter/constants'
2
+ require 'opening_hours_converter/utils'
2
3
  require 'json'
3
4
 
4
5
  module OpeningHoursConverter
5
6
  class OpeningHoursParser
6
7
  include Constants
8
+ include Utils
7
9
 
8
10
  def initialize
9
11
  @RGX_RULE_MODIFIER = /^(open|closed|off)$/i
10
12
  @RGX_WEEK_KEY = /^week$/
11
- @RGX_WEEK_VAL = /^([01234]?[0-9]|5[0123])(\-([01234]?[0-9]|5[0123]))?(,([01234]?[0-9]|5[0123])(\-([01234]?[0-9]|5[0123]))?)*\:?$/
13
+ @RGX_WEEK = /^week ([01234]?[0-9]|5[0123])(\-([01234]?[0-9]|5[0123]))?(, ?([01234]?[0-9]|5[0123])(\-([01234]?[0-9]|5[0123]))?)*$/
14
+ @RGX_WEEK_VAL = /^([01234]?[0-9]|5[0123])(\-([01234]?[0-9]|5[0123]))?(, ?([01234]?[0-9]|5[0123])(\-([01234]?[0-9]|5[0123]))?)*$/
15
+ @RGX_WEEK_WITH_MODIFIER = /^week ([01234]?[0-9]|5[0123])(\-([01234]?[0-9]|5[0123])(\/[1-9])?)?(, ?([01234]?[0-9]|5[0123])(\-([01234]?[0-9]|5[0123])(\/[1-9])?)?)*$/
16
+ @RGX_WEEK_VAL_WITH_MODIFIER = /^([01234]?[0-9]|5[0123])(\-([01234]?[0-9]|5[0123])(\/[1-9])?)?(, ?([01234]?[0-9]|5[0123])(\-([01234]?[0-9]|5[0123])(\/[1-9])?)?)*$/
12
17
  @RGX_MONTH = /^(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)(\-(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec))?\:?$/
13
18
  @RGX_MONTHDAY = /^(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec) ([012]?[0-9]|3[01])(\-((Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec) )?([012]?[0-9]|3[01]))?\:?$/
14
19
  @RGX_TIME = /^((([01]?[0-9]|2[01234])\:[012345][0-9](\-([01]?[0-9]|2[01234])\:[012345][0-9])?(,([01]?[0-9]|2[01234])\:[012345][0-9](\-([01]?[0-9]|2[01234])\:[012345][0-9])?)*)|(24\/7))$/
15
20
  @RGX_WEEKDAY = /^(((Mo|Tu|We|Th|Fr|Sa|Su)(\-(Mo|Tu|We|Th|Fr|Sa|Su))?)|(PH))(,(((Mo|Tu|We|Th|Fr|Sa|Su)(\-(Mo|Tu|We|Th|Fr|Sa|Su))?)|(PH)))*$/
16
21
  @RGX_HOLIDAY = /^(PH|SH|easter)$/
17
22
  @RGX_WD = /^(Mo|Tu|We|Th|Fr|Sa|Su)(\-(Mo|Tu|We|Th|Fr|Sa|Su))?$/
23
+ @RGX_WD_WITH_MODIFIER = /^(Mo|Tu|We|Th|Fr|Sa|Su)\[([1-5]|\-1)\]$/
18
24
  @RGX_DAY = /^([012]?[0-9]|3[01])(\-[012]?[0-9]|3[01])?$/
19
25
  @RGX_YEAR = /^(\d{4})(\-(\d{4}))?$/
20
26
  @RGX_YEAR_PH = /^(\d{4})( PH|(\-(\d{4}) PH))\:?$/
27
+ @RGX_YEAR_WEEK = /^(\d{4})(\-(\d{4}))? week ([01234]?[0-9]|5[0123])(\-([01234]?[0-9]|5[0123]))?(, ?([01234]?[0-9]|5[0123])(\-([01234]?[0-9]|5[0123]))?)*\:?$/
28
+ @RGX_YEAR_WEEK_WITH_MODIFIER = /^(\d{4})(\-(\d{4}))? week ([01234]?[0-9]|5[0123])(\-([01234]?[0-9]|5[0123])(\/[1-9])?)?(, ?([01234]?[0-9]|5[0123])(\-([01234]?[0-9]|5[0123])(\/[1-9])?)?)*$/
21
29
  @RGX_YEAR_MONTH_DAY = /^(\d{4}) (Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec) ([012]?[0-9]|3[01])(\-((\d{4}) )?((Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec) )?([012]?[0-9]|3[01]))?\:?$/
22
30
  @RGX_YEAR_MONTH = /^(\d{4}) (Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)(\-((\d{4}) )?((Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)))?\:?$/
23
31
  @RGX_COMMENT = /^\"[^\"]*\"$/
@@ -45,7 +53,9 @@ module OpeningHoursConverter
45
53
  block.strip!
46
54
  next if block.empty?
47
55
 
48
- tokens = tokenize(block)
56
+ tokenizer = OpeningHoursConverter::Tokenizer.new(block)
57
+ tokens = tokenizer.tokens
58
+ # tokens = tokenize(block)
49
59
  @current_token = tokens.length - 1
50
60
 
51
61
  weekdays = {}
@@ -66,9 +76,9 @@ module OpeningHoursConverter
66
76
  weekday_selector = tokens[@current_token]
67
77
  weekdays_and_holidays = get_weekdays(weekday_selector)
68
78
  rescue StandardError
69
- weekdays[[{ from: 0, to: 6 }]] ||= {}
70
- weekdays[[{ from: 0, to: 6 }]][:modifiers] ||= []
71
- weekdays[[{ from: 0, to: 6 }]][:modifiers] << local_modifier
79
+ weekdays[[{ from: 0, to: 6, index: nil }]] ||= {}
80
+ weekdays[[{ from: 0, to: 6, index: nil }]][:modifiers] ||= []
81
+ weekdays[[{ from: 0, to: 6, index: nil }]][:modifiers] << local_modifier
72
82
  else
73
83
  weekdays[weekdays_and_holidays] ||= {}
74
84
  weekdays[weekdays_and_holidays][:modifiers] ||= []
@@ -86,9 +96,9 @@ module OpeningHoursConverter
86
96
  weekday_selector = tokens[@current_token]
87
97
  weekdays_and_holidays = get_weekdays(weekday_selector)
88
98
  rescue StandardError
89
- weekdays[[{ from: 0, to: 6 }]] ||= {}
90
- weekdays[[{ from: 0, to: 6 }]][:times] ||= []
91
- weekdays[[{ from: 0, to: 6 }]][:times].concat(local_times)
99
+ weekdays[[{ from: 0, to: 6, index: nil }]] ||= {}
100
+ weekdays[[{ from: 0, to: 6, index: nil }]][:times] ||= []
101
+ weekdays[[{ from: 0, to: 6, index: nil }]][:times].concat(local_times)
92
102
  else
93
103
  weekdays[weekdays_and_holidays] ||= {}
94
104
  weekdays[weekdays_and_holidays][:times] ||= []
@@ -98,6 +108,7 @@ module OpeningHoursConverter
98
108
  end
99
109
  end
100
110
 
111
+ weeks = []
101
112
  months = []
102
113
  years = []
103
114
  holidays = []
@@ -108,21 +119,27 @@ module OpeningHoursConverter
108
119
  end
109
120
  if !wide_range_selector.empty?
110
121
  wide_range_selector = wide_range_selector.strip
111
- wide_range_selector = wide_range_selector.split(',')
112
- wide_range_selector.each do |wrs|
113
- if !(@RGX_YEAR_MONTH_DAY =~ wrs).nil?
114
- years << get_year_month_day(wrs)
115
- elsif !(@RGX_YEAR_MONTH =~ wrs).nil?
116
- years << get_year_month(wrs)
117
- elsif !(@RGX_MONTHDAY =~ wrs).nil?
118
- months << get_month_day(wrs)
119
- elsif !(@RGX_MONTH =~ wrs).nil?
120
- months << get_month(wrs)
121
- elsif !(@RGX_YEAR =~ wrs).nil?
122
- years << get_year(wrs)
123
- else
124
- raise ArgumentError, "Unsupported selector #{wrs}"
125
- end
122
+ # wide_range_selector = wide_range_selector.split(',')
123
+ if !(@RGX_YEAR_MONTH_DAY =~ wide_range_selector).nil?
124
+ years << get_year_month_day(wide_range_selector)
125
+ elsif !(@RGX_YEAR_MONTH =~ wide_range_selector).nil?
126
+ years << get_year_month(wide_range_selector)
127
+ elsif !(@RGX_MONTHDAY =~ wide_range_selector).nil?
128
+ months << get_month_day(wide_range_selector)
129
+ elsif !(@RGX_MONTH =~ wide_range_selector).nil?
130
+ months << get_month(wide_range_selector)
131
+ elsif !(@RGX_YEAR =~ wide_range_selector).nil?
132
+ years << get_year(wide_range_selector)
133
+ elsif !(@RGX_YEAR_WEEK_WITH_MODIFIER =~ wide_range_selector).nil?
134
+ weeks << get_year_week_with_modifier(wide_range_selector)
135
+ elsif !(@RGX_YEAR_WEEK =~ wide_range_selector).nil?
136
+ weeks << get_year_week(wide_range_selector)
137
+ elsif !(@RGX_WEEK_WITH_MODIFIER =~ wide_range_selector).nil?
138
+ weeks << get_week_with_modifier(wide_range_selector)
139
+ elsif !(@RGX_WEEK =~ wide_range_selector).nil?
140
+ weeks << get_week(wide_range_selector)
141
+ else
142
+ raise ArgumentError, "Unsupported selector #{wide_range_selector}"
126
143
  end
127
144
  end
128
145
  end
@@ -130,6 +147,7 @@ module OpeningHoursConverter
130
147
  raise ArgumentError, 'Unreadable string' if @current_token == tokens.length - 1
131
148
 
132
149
  # puts "weekdays : #{weekdays}"
150
+ # puts "weeks : #{weeks}"
133
151
  # puts "months : #{months}"
134
152
  # puts "years : #{years}"
135
153
 
@@ -152,6 +170,12 @@ module OpeningHoursConverter
152
170
  end
153
171
  date_ranges << date_range
154
172
  end
173
+ elsif !weeks.empty?
174
+
175
+ weeks.each do |week|
176
+ date_ranges << OpeningHoursConverter::WideInterval.new.week(week[:week_indexes], week[:year_from], week[:year_to])
177
+ end
178
+
155
179
  elsif !years.empty?
156
180
  years.each do |year|
157
181
  if !year[:from_day].nil?
@@ -182,8 +206,8 @@ module OpeningHoursConverter
182
206
  end
183
207
 
184
208
  if weekdays.empty?
185
- weekdays[[{ from: 0, to: 6 }]] = {}
186
- weekdays[[{ from: 0, to: 6 }]][:times] = [{ from: 0, to: 24 * 60 }]
209
+ weekdays[[{ from: 0, to: 6, index: nil }]] = {}
210
+ weekdays[[{ from: 0, to: 6, index: nil }]][:times] = [{ from: 0, to: 24 * 60 }]
187
211
  end
188
212
 
189
213
  date_ranges.each do |dr|
@@ -280,7 +304,14 @@ module OpeningHoursConverter
280
304
  if end_interval.day == start_interval.day + 1 && end_interval.hour == 0 && end_interval.min == 0
281
305
  end_interval -= (1 / 1440.0)
282
306
  end
283
- date_range.last.typical.add_interval(OpeningHoursConverter::Interval.new(((start_interval.wday + 6) % 7), (start_interval.hour * 60 + start_interval.min), ((end_interval.wday + 6) % 7), (end_interval.hour * 60 + end_interval.min)))
307
+ date_range.last.typical.add_interval(
308
+ OpeningHoursConverter::Interval.new(
309
+ reindex_sunday_week_to_monday_week(start_interval.wday),
310
+ (start_interval.hour * 60 + start_interval.min),
311
+ reindex_sunday_week_to_monday_week(end_interval.wday),
312
+ (end_interval.hour * 60 + end_interval.min)
313
+ )
314
+ )
284
315
  end
285
316
  end
286
317
  date_range
@@ -300,6 +331,86 @@ module OpeningHoursConverter
300
331
  { from: year_from, to: year_to }
301
332
  end
302
333
 
334
+ def get_year_week_with_modifier(wrs)
335
+ year, weeks = wrs.split(' week ')
336
+ years = year.split('-')
337
+
338
+ indexes = weeks.split(',').map { |week_index|
339
+ if week_index.include?('-')
340
+ if week_index.include?('/')
341
+ from, to = week_index.split('-')
342
+ to, modifier = to.split('/')
343
+ { from: from.to_i, to: to.to_i, modifier: modifier.to_i }
344
+ else
345
+ from, to = week_index.split('-').map(&:to_i)
346
+ { from: from, to: to }
347
+ end
348
+ else
349
+ week_index.to_i
350
+ end
351
+ }
352
+
353
+ { year_from: years[0].to_i, week_indexes: indexes }.tap do |hsh|
354
+ hsh[:year_to] = years.length > 1 ? years[1].to_i : nil
355
+ end
356
+ end
357
+
358
+ def get_year_week(wrs)
359
+ year, weeks = wrs.split(' week ')
360
+ # does not handle 2018,2019
361
+ years = year.split('-')
362
+ # does not handle week 1,2,3
363
+ indexes = weeks.split(',').map { |week_index|
364
+ if week_index.include?('-')
365
+ from, to = week_index.split('-').map(&:to_i)
366
+ { from: from, to: to }
367
+ else
368
+ week_index.to_i
369
+ end
370
+ }
371
+
372
+ { week_indexes: indexes, year_from: year[0].to_i }.tap do |hsh|
373
+ hsh[:year_to] = years.length > 1 ? year[1].to_i : nil
374
+ end
375
+ end
376
+
377
+ def get_week_with_modifier(wrs)
378
+ weeks = wrs.gsub('week ', '').split(',')
379
+
380
+ indexes = weeks.map { |week_index|
381
+ if week_index.include?('-')
382
+ if week_index.include?('/')
383
+ from, to = week_index.split('-')
384
+ to, modifier = to.split('/')
385
+ { from: from.to_i, to: to.to_i, modifier: modifier.to_i }
386
+ else
387
+ from, to = week_index.split('-').map(&:to_i)
388
+ { from: from, to: to }
389
+ end
390
+ else
391
+ week_index.to_i
392
+ end
393
+ }
394
+
395
+ { week_indexes: indexes }
396
+ end
397
+
398
+ def get_week(wrs)
399
+ weeks = wrs.gsub('week ', '').split(',')
400
+
401
+ indexes = weeks.map { |week_index|
402
+ if week_index.include?('-')
403
+ from, to = week_index.split('-').map(&:to_i)
404
+ { from: from, to: to }
405
+ else
406
+ week_index.to_i
407
+ end
408
+ }
409
+
410
+ { week_indexes: indexes }
411
+ end
412
+
413
+
303
414
  def get_month(wrs)
304
415
  single_month = wrs.gsub(/\:$/, '').split('-')
305
416
  month_from = OSM_MONTHS.find_index(single_month[0]) + 1
@@ -429,9 +540,10 @@ module OpeningHoursConverter
429
540
  wd_to = nil
430
541
 
431
542
  weekday_selector = weekday_selector.split(',')
543
+
432
544
  weekday_selector.each do |wd|
433
545
  if !(@RGX_HOLIDAY =~ wd).nil?
434
- weekdays << { from: -2, to: -2 }
546
+ weekdays << { from: -2, to: -2, index: nil }
435
547
  elsif !(@RGX_WD =~ wd).nil?
436
548
  single_weekday = wd.split('-')
437
549
 
@@ -442,7 +554,16 @@ module OpeningHoursConverter
442
554
  wd_from
443
555
  end
444
556
 
445
- weekdays << { from: wd_from, to: wd_to }
557
+ weekdays << { from: wd_from, to: wd_to, index: nil }
558
+ elsif !(@RGX_WD_WITH_MODIFIER =~ wd).nil?
559
+
560
+ from, to = wd[0...wd.index('[')].split('-')
561
+ index = wd[wd.index('[') + 1...wd.index(']')]
562
+
563
+ wd_from = OSM_DAYS.find_index(from)
564
+ wd_to = OSM_DAYS.find_index(to)
565
+
566
+ weekdays << { from: wd_from, to: wd_from, index: index.to_i }
446
567
  else
447
568
  raise ArgumentError, "Invalid weekday interval : #{wd}"
448
569
  end
@@ -564,6 +685,7 @@ module OpeningHoursConverter
564
685
  weekday_merge = []
565
686
  wide_interval_merge = []
566
687
  merged_wide_interval = []
688
+
567
689
  groups.each_with_index do |group, group_index|
568
690
  if !wide_interval_merge.empty?
569
691
  merged_wide_interval += [wide_interval_merge.join(' ')]
@@ -575,7 +697,7 @@ module OpeningHoursConverter
575
697
  wide_interval_merge = []
576
698
  new_tokens << merged_wide_interval.join(',')
577
699
  end
578
- if is_weekday?(token)
700
+ if is_weekday?(token) || is_weekday_with_modifier?(token)
579
701
  weekday_merge << token
580
702
  if token_index == group.length - 1 && group_index == groups.length - 1
581
703
  new_tokens << weekday_merge.join(',')
@@ -606,7 +728,10 @@ module OpeningHoursConverter
606
728
  def is_part_of_wide_interval?(string)
607
729
  is_wide_interval = false
608
730
  string.split('-').each do |str|
609
- if (!(@RGX_YEAR =~ str).nil? || !(@RGX_YEAR_MONTH =~ str).nil? || !(@RGX_YEAR_MONTH_DAY =~ str).nil? || !(@RGX_DAY =~ str).nil? || !(@RGX_MONTHDAY =~ str).nil? || !(@RGX_MONTH =~ str).nil?) && ((@RGX_TIME =~ str).nil? && (@RGX_WEEKDAY =~ str).nil?)
731
+ if (!(@RGX_YEAR =~ str).nil? || !(@RGX_YEAR_MONTH =~ str).nil? || !(@RGX_YEAR_MONTH_DAY =~ str).nil? ||
732
+ !(@RGX_DAY =~ str).nil? || !(@RGX_MONTHDAY =~ str).nil? || !(@RGX_MONTH =~ str).nil? ||
733
+ !(@RGX_WEEK_KEY =~ str).nil? || !(@RGX_WEEK_VAL =~ str).nil? || !(@RGX_WEEK_VAL_WITH_MODIFIER =~ str).nil?) &&
734
+ ((@RGX_TIME =~ str).nil? && (@RGX_WEEKDAY =~ str).nil?)
610
735
  is_wide_interval = true
611
736
  else
612
737
  return false
@@ -635,8 +760,38 @@ module OpeningHoursConverter
635
760
  !(@RGX_WEEKDAY =~ token).nil?
636
761
  end
637
762
 
763
+ def is_weekday_with_modifier?(token)
764
+ !(@RGX_WD_WITH_MODIFIER =~ token).nil?
765
+ end
766
+
638
767
  def is_year?(token)
639
768
  !(@RGX_YEAR =~ token).nil?
640
769
  end
770
+
771
+ def is_week_key?(token)
772
+ !(@RGX_WEEK_KEY =~ token).nil?
773
+ end
774
+
775
+ def is_week_val?(token)
776
+ !(@RGX_WEEK_VAL =~ token).nil?
777
+ end
778
+
779
+ def is_week_with_modifier?(token)
780
+ !(@RGX_WEEK_WITH_MODIFIER =~ token).nil?
781
+ end
782
+
783
+ def is_week_val_with_modifier?(token)
784
+ !(@RGX_WEEK_VAL_WITH_MODIFIER =~ token).nil?
785
+ end
786
+
787
+ def is_year_week?(token)
788
+ !(@RGX_YEAR_WEEK =~ token).nil?
789
+ end
790
+
791
+ def is_year_week_with_modifier?(token)
792
+ !(@RGX_YEAR_WEEK_WITH_MODIFIER =~ token).nil?
793
+ end
641
794
  end
642
795
  end
796
+
797
+
@@ -61,6 +61,8 @@ module OpeningHoursConverter
61
61
  month_start = -1
62
62
  day_start = -1
63
63
 
64
+ return result_to_string(years) if is_only_week_interval?(years)
65
+
64
66
  result = {}
65
67
 
66
68
  if !years['always'].nil?
@@ -120,7 +122,7 @@ module OpeningHoursConverter
120
122
  { day: 30, month: 11 }
121
123
  else
122
124
  { day: MONTH_END_DAY[month - 1] - 1, month: month - 1 }
123
- end
125
+ end
124
126
  else
125
127
  { day: day - 1, month: month }
126
128
  end
@@ -148,63 +150,90 @@ module OpeningHoursConverter
148
150
 
149
151
  def result_to_string(result)
150
152
  str_result = ''
151
- result.each do |selector, intervals|
152
- if selector == 'always'
153
- intervals.each do |interval|
154
- str_result += ',' if !str_result.empty?
155
- if is_full_year?(interval)
156
- elsif is_full_month?(interval)
157
- str_result += (OSM_MONTHS[interval[:start][:month]]).to_s
158
- elsif starts_month?(interval) && ends_month?(interval)
159
- str_result += "#{OSM_MONTHS[interval[:start][:month]]}-#{OSM_MONTHS[interval[:end][:month]]}"
160
- elsif is_same_month?(interval)
161
- if is_same_day?(interval)
162
- str_result += "#{OSM_MONTHS[interval[:start][:month]]} #{interval[:start][:day] + 1 < 10 ? "0#{interval[:start][:day] + 1}" : interval[:start][:day] + 1}"
153
+ if is_only_week_interval?(result)
154
+ local_str = result.keys == ['always'] ? 'week ' : result.keys.length == 1 ? result.keys.first.to_s + ' week ' : result.keys.min.to_s + '-' + result.keys.max.to_s + ' week '
155
+
156
+ intervals = result[result.keys.first]
157
+ intervals.each do |interval|
158
+ local_str += "," if !(local_str[local_str.length - 1] =~ /^[0-9]$/).nil?
159
+ local_str +=
160
+ if interval[:modifier].nil?
161
+ if interval[:start][:week] == interval[:end][:week]
162
+ interval[:start][:week].to_s
163
163
  else
164
- str_result += "#{OSM_MONTHS[interval[:start][:month]]} #{interval[:start][:day] + 1 < 10 ? "0#{interval[:start][:day] + 1}" : interval[:start][:day] + 1}-#{interval[:end][:day] + 1 < 10 ? "0#{interval[:end][:day] + 1}" : interval[:end][:day] + 1}"
164
+ "#{interval[:start][:week].to_s + '-' + interval[:end][:week].to_s}"
165
165
  end
166
166
  else
167
- str_result += "#{OSM_MONTHS[interval[:start][:month]]} #{interval[:start][:day] + 1 < 10 ? "0#{interval[:start][:day] + 1}" : interval[:start][:day] + 1}-#{OSM_MONTHS[interval[:end][:month]]} #{interval[:end][:day] + 1 < 10 ? "0#{interval[:end][:day] + 1}" : interval[:end][:day] + 1}"
167
+ "#{interval[:start][:week].to_s + '-' + interval[:end][:week].to_s}/#{interval[:modifier].to_s}"
168
168
  end
169
- end
170
- elsif selector == 'multi_year'
171
- intervals.each do |_years, intervals|
169
+ end
170
+ str_result += local_str
171
+ else
172
+ result.each do |selector, intervals|
173
+ if selector == 'always'
172
174
  intervals.each do |interval|
173
175
  str_result += ',' if !str_result.empty?
174
- if starts_year?(interval) && ends_year?(interval)
176
+ if is_full_year?(interval)
177
+ elsif starts_year?(interval) && ends_year?(interval)
175
178
  str_result += "#{interval[:start][:year]}-#{interval[:end][:year]}"
176
- # elsif starts_month?(interval) && ends_month?(interval)
177
- # str_result += "#{interval[:start][:year]} #{OSM_MONTHS[interval[:start][:month]]}-#{interval[:end][:year]} #{OSM_MONTHS[interval[:end][:month]]}"
179
+ elsif is_full_month?(interval)
180
+ str_result += (OSM_MONTHS[interval[:start][:month]]).to_s
181
+ elsif is_same_month?(interval)
182
+ if is_same_day?(interval)
183
+ str_result += "#{OSM_MONTHS[interval[:start][:month]]} #{interval[:start][:day] + 1 < 10 ? "0#{interval[:start][:day] + 1}" : interval[:start][:day] + 1}"
184
+ else
185
+ str_result += "#{OSM_MONTHS[interval[:start][:month]]} #{interval[:start][:day] + 1 < 10 ? "0#{interval[:start][:day] + 1}" : interval[:start][:day] + 1}-#{interval[:end][:day] + 1 < 10 ? "0#{interval[:end][:day] + 1}" : interval[:end][:day] + 1}"
186
+ end
187
+ elsif starts_month?(interval) && ends_month?(interval)
188
+ str_result += "#{OSM_MONTHS[interval[:start][:month]]}-#{OSM_MONTHS[interval[:end][:month]]}"
178
189
  else
179
- str_result += "#{interval[:start][:year]} #{OSM_MONTHS[interval[:start][:month]]} #{interval[:start][:day] + 1 < 10 ? "0#{interval[:start][:day] + 1}" : interval[:start][:day] + 1}-#{interval[:end][:year]} #{OSM_MONTHS[interval[:end][:month]]} #{interval[:end][:day] + 1 < 10 ? "0#{interval[:end][:day] + 1}" : interval[:end][:day] + 1}"
190
+ str_result += "#{OSM_MONTHS[interval[:start][:month]]} #{interval[:start][:day] + 1 < 10 ? "0#{interval[:start][:day] + 1}" : interval[:start][:day] + 1}-#{OSM_MONTHS[interval[:end][:month]]} #{interval[:end][:day] + 1 < 10 ? "0#{interval[:end][:day] + 1}" : interval[:end][:day] + 1}"
180
191
  end
181
192
  end
182
- end
183
- else
184
- local_str = "#{selector} "
185
- intervals.each do |interval|
186
- if is_full_year?(interval)
187
- # elsif
188
- # local_str += "#{local_str.length > 5 ? "," : ""}#{OSM_MONTHS[interval[:start][:month]]}"
189
- # elsif
190
- # local_str += "#{local_str.length > 5 ? "," : ""}#{OSM_MONTHS[interval[:start][:month]]}-#{OSM_MONTHS[interval[:end][:month]]}"
191
- elsif is_same_month?(interval)
192
- if is_same_day?(interval)
193
- local_str += "#{local_str.length > 5 ? ',' : ''}#{OSM_MONTHS[interval[:start][:month]]} #{interval[:start][:day] + 1 < 10 ? "0#{interval[:start][:day] + 1}" : interval[:start][:day] + 1}"
193
+ elsif selector == 'multi_year'
194
+ intervals.each do |_years, intervals|
195
+ intervals.each do |interval|
196
+ str_result += ',' if !str_result.empty?
197
+ if starts_year?(interval) && ends_year?(interval)
198
+ str_result += "#{interval[:start][:year]}-#{interval[:end][:year]}"
199
+ else
200
+ str_result += "#{interval[:start][:year]} #{OSM_MONTHS[interval[:start][:month]]} #{interval[:start][:day] + 1 < 10 ? "0#{interval[:start][:day] + 1}" : interval[:start][:day] + 1}-#{interval[:end][:year]} #{OSM_MONTHS[interval[:end][:month]]} #{interval[:end][:day] + 1 < 10 ? "0#{interval[:end][:day] + 1}" : interval[:end][:day] + 1}"
201
+ end
202
+ end
203
+ end
204
+ else
205
+ local_str = "#{selector} "
206
+ intervals.each do |interval|
207
+ if is_full_year?(interval)
208
+ elsif is_same_month?(interval)
209
+ if is_same_day?(interval)
210
+ local_str += "#{local_str.length > 5 ? ',' : ''}#{OSM_MONTHS[interval[:start][:month]]} #{interval[:start][:day] + 1 < 10 ? "0#{interval[:start][:day] + 1}" : interval[:start][:day] + 1}"
211
+ else
212
+ local_str += "#{local_str.length > 5 ? ',' : ''}#{OSM_MONTHS[interval[:start][:month]]} #{interval[:start][:day] + 1 < 10 ? "0#{interval[:start][:day] + 1}" : interval[:start][:day] + 1}-#{interval[:end][:day] + 1 < 10 ? "0#{interval[:end][:day] + 1}" : interval[:end][:day] + 1}"
213
+ end
194
214
  else
195
- local_str += "#{local_str.length > 5 ? ',' : ''}#{OSM_MONTHS[interval[:start][:month]]} #{interval[:start][:day] + 1 < 10 ? "0#{interval[:start][:day] + 1}" : interval[:start][:day] + 1}-#{interval[:end][:day] + 1 < 10 ? "0#{interval[:end][:day] + 1}" : interval[:end][:day] + 1}"
215
+ local_str += "#{local_str.length > 5 ? ',' : ''}#{OSM_MONTHS[interval[:start][:month]]} #{interval[:start][:day] + 1 < 10 ? "0#{interval[:start][:day] + 1}" : interval[:start][:day] + 1}-#{selector} #{OSM_MONTHS[interval[:end][:month]]} #{interval[:end][:day] + 1 < 10 ? "0#{interval[:end][:day] + 1}" : interval[:end][:day] + 1}"
196
216
  end
197
- else
198
- local_str += "#{local_str.length > 5 ? ',' : ''}#{OSM_MONTHS[interval[:start][:month]]} #{interval[:start][:day] + 1 < 10 ? "0#{interval[:start][:day] + 1}" : interval[:start][:day] + 1}-#{selector} #{OSM_MONTHS[interval[:end][:month]]} #{interval[:end][:day] + 1 < 10 ? "0#{interval[:end][:day] + 1}" : interval[:end][:day] + 1}"
217
+ str_result += "#{!str_result.empty? ? ',' : ''}#{local_str}"
199
218
  end
200
219
  end
201
- str_result += "#{!str_result.empty? ? ',' : ''}#{local_str}"
202
220
  end
203
221
  end
204
222
 
205
223
  str_result.strip
206
224
  end
207
225
 
226
+ def is_only_week_interval?(r)
227
+ r.all? do |year, intervals|
228
+ intervals.all? do |interval|
229
+ is_week_interval?(interval)
230
+ end
231
+ end
232
+ end
233
+ def is_week_interval?(interval)
234
+ !interval.is_a?(Array) && interval.key?(:start) && interval[:start].key?(:week)
235
+ end
236
+
208
237
  def is_full_year?(r)
209
238
  starts_year?(r) && ends_year?(r)
210
239
  end
@@ -3,11 +3,12 @@ require 'opening_hours_converter/constants'
3
3
  module OpeningHoursConverter
4
4
  class WideInterval
5
5
  include Constants
6
- attr_accessor :start, :end, :type
6
+ attr_accessor :start, :end, :type, :indexes
7
7
 
8
8
  def initialize
9
9
  @start = nil
10
10
  @end = nil
11
+ @indexes = nil
11
12
  @type = nil
12
13
  end
13
14
 
@@ -87,13 +88,11 @@ module OpeningHoursConverter
87
88
  'jours fériés'
88
89
  else
89
90
  "les jours fériés de #{@start[:year]} à #{@end[:year]}"
90
- end
91
+ end
92
+ elsif !@start[:year]
93
+ 'jours fériés'
91
94
  else
92
- if !@start[:year]
93
- 'jours fériés'
94
- else
95
- "les jours fériés de #{@start[:year]}"
96
- end
95
+ "les jours fériés de #{@start[:year]}"
97
96
  end
98
97
  when 'always'
99
98
  result = 'tout le temps'
@@ -135,6 +134,17 @@ module OpeningHoursConverter
135
134
  self
136
135
  end
137
136
 
137
+ def week(week_indexes, start_year = nil, end_year = nil)
138
+ raise(ArgumentError, 'weeks are required (array of ints)') if week_indexes.nil? || !week_indexes.is_a?(Array)
139
+ @start = { year: start_year }
140
+ @indexes = week_indexes
141
+ if !start_year.nil? && !end_year.nil? && end_year != start_year
142
+ @end = { year: end_year }
143
+ end
144
+ @type = 'week'
145
+ self
146
+ end
147
+
138
148
  def year(start_year, end_year = nil)
139
149
  raise(ArgumentError, 'start_year is required') if start_year.nil?
140
150
  @start = { year: start_year }
@@ -212,6 +222,17 @@ module OpeningHoursConverter
212
222
  else
213
223
  my = to_day
214
224
  o = o.to_day
225
+
226
+ if my.is_a?(Array)
227
+ if o.is_a?(Array)
228
+ return false
229
+ else
230
+ return my.all? { |day| day.contains?(o) }
231
+ end
232
+ elsif o.is_a?(Array)
233
+ return o.all? { |day| contains?(day) }
234
+ end
235
+
215
236
  result = has_superior_or_equal_start_day?(my, o) && has_inferior_or_equal_end_day?(my, o)
216
237
  end
217
238
  result
@@ -227,6 +248,22 @@ module OpeningHoursConverter
227
248
  my = to_day
228
249
  o = o.to_day
229
250
 
251
+ if my.is_a?(Array)
252
+ if o.is_a?(Array)
253
+ return my.any? do |day|
254
+ o.any? do |o_day|
255
+ day.touch?(o_day)
256
+ end
257
+ end
258
+ else
259
+ return my.any? { |day| day.touch?(o) }
260
+ end
261
+ elsif o.is_a?(Array)
262
+ return o.any? { |day| day.touch?(my) }
263
+ end
264
+ # solution poour les weeks, on peut convertir un wide interval week en array de wide interval days et comparer les wide interval week
265
+ # un par un (long si deux wide interval multiweek)
266
+ # problem : comment calculer les weeks always ? comparer sur l'année en cours si o est always, les années de o sinon
230
267
  result = ((my_start_is_before_o_end?(my, o) && my_start_is_after_o_start?(my, o)) ||
231
268
  (my_end_is_before_o_end?(my, o) && my_end_is_after_o_start?(my, o))) ||
232
269
  ((my_start_is_before_o_end?(o, my) && my_start_is_after_o_start?(o, my)) ||
@@ -390,10 +427,33 @@ module OpeningHoursConverter
390
427
  o.start[:day] >= my.start[:day]))
391
428
  end
392
429
 
430
+ def sort_days_array(days_array, by = :start)
431
+ if days_array.all? { |day| day.start && !day.start[:year].nil? }
432
+ days_array.sort_by { |day| [day.send(by)[:year], day.send(by)[:month], day.send(by)[:day]] }
433
+ else
434
+ days_array.sort_by { |day| [day.send(by)[:month], day.send(by)[:day]] }
435
+ end
436
+
437
+ end
438
+
393
439
  def has_superior_or_equal_start_day?(my, o)
394
440
  result = false
395
441
  if has_start_year?(o) && has_start_year?(my)
396
- result = o.start[:year] > my.start[:year] || (o.start[:year] == my.start[:year] && has_superior_start_month?(my, o))
442
+ if o.is_a?(Array)
443
+ if my.is_a?(Array)
444
+ o = sort_days_array o
445
+ my = sort_days_array my
446
+ has_superior_or_equal_start_day?(my.first, o.first)
447
+ else
448
+ o = sort_days_array o
449
+ has_superior_or_equal_start_day?(my, o.first)
450
+ end
451
+ elsif my.is_a?(Array)
452
+ my = sort_days_array my
453
+ has_superior_or_equal_start_day?(my.first, o)
454
+ else
455
+ result = o.start[:year] > my.start[:year] || (o.start[:year] == my.start[:year] && has_superior_start_month?(my, o))
456
+ end
397
457
  elsif !has_start_year?(my)
398
458
  result = has_superior_start_month?(my, o)
399
459
  end
@@ -433,7 +493,11 @@ module OpeningHoursConverter
433
493
  end
434
494
 
435
495
  def has_start_year?(date)
436
- !date.start[:year].nil?
496
+ if date.is_a?(Array)
497
+ date.all? { |d| !d.start[:year].nil? }
498
+ else
499
+ !date.start[:year].nil?
500
+ end
437
501
  end
438
502
 
439
503
  def has_end_year?(date)
@@ -450,6 +514,23 @@ module OpeningHoursConverter
450
514
  return false if @type == 'always'
451
515
  self_to_day = to_day
452
516
  o_to_day = o.to_day
517
+ return false if self_to_day.is_a?(Array) != o_to_day.is_a?(Array)
518
+
519
+ if self_to_day.is_a?(Array)
520
+ if o_to_day.is_a?(Array)
521
+ return false unless o_to_day.length == self_to_day.length
522
+ return self_to_day.all? do |self_day|
523
+ o_to_day.any? do |o_day|
524
+ self_day.equals(o_day)
525
+ end
526
+ end
527
+ else
528
+ return self_to_day.all? { |day| self_to_day.equals(o_to_day) }
529
+ end
530
+ elsif o_to_day.is_a?(Array)
531
+ return o_to_day.all? { |day| equals(day) }
532
+ end
533
+
453
534
  (self_to_day.start[:year] == o_to_day.start[:year] &&
454
535
  self_to_day.start[:month] == o_to_day.start[:month] &&
455
536
  self_to_day.start[:day] == o_to_day.start[:day]) &&
@@ -461,8 +542,11 @@ module OpeningHoursConverter
461
542
 
462
543
  def width
463
544
  return Float::INFINITY if @type == 'always'
545
+
464
546
  in_day = to_day
465
547
  days_count = 0
548
+ return in_day.map(&:width).sum if in_day.is_a?(Array)
549
+
466
550
  if in_day.end
467
551
  if in_day.start[:year] && in_day.end[:year]
468
552
  if in_day.start[:year] != in_day.end[:year]
@@ -541,6 +625,7 @@ module OpeningHoursConverter
541
625
  end
542
626
 
543
627
  def to_day
628
+ # les semaines rentrent en opposition avec cette maniere de faire : il n'y a pas un debut et une fin il y en a plusieurs (1-53/2)
544
629
  case @type
545
630
  when 'day'
546
631
  if @end.nil?
@@ -560,6 +645,70 @@ module OpeningHoursConverter
560
645
  else
561
646
  OpeningHoursConverter::WideInterval.new.day(1, 1, @start[:year], 31, 12, @end[:year])
562
647
  end
648
+ when 'holiday'
649
+ if @start && @start[:year]
650
+ if @end && @end[:year]
651
+ weeks = []
652
+ (@start[:year]..@end[:year]).each do |year|
653
+ weeks += get_public_holidays_for_year(year)
654
+ end
655
+ weeks
656
+ else
657
+ get_public_holidays_for_year(@start[:year])
658
+ end
659
+ else
660
+ get_public_holidays_for_year
661
+ end
662
+ when 'week'
663
+ if @start && @start[:year]
664
+ if @end && @end[:year]
665
+ weeks = []
666
+ (@start[:year]..@end[:year]).each do |year|
667
+ weeks += get_weeks_for_year(year)
668
+ end
669
+ weeks
670
+ else
671
+ get_weeks_for_year(@start[:year])
672
+ end
673
+ else
674
+ get_weeks_for_year
675
+ end
676
+ end
677
+ end
678
+
679
+ def get_weeks_for_year(year = Time.now.year)
680
+ weeks_as_days = []
681
+ @indexes.each do |week_index|
682
+ if week_index.is_a?(Integer)
683
+ week = OpeningHoursConverter::WeekIndex.week_from_index(week_index, year)
684
+ weeks_as_days << OpeningHoursConverter::WideInterval.new.day(week[:from].day, week[:from].month, week[:from].year,
685
+ week[:to].day, week[:to].month, week[:to].year)
686
+ else
687
+ if week_index.key?(:modifier)
688
+ i = 0
689
+ (week_index[:from]..week_index[:to]).map do |index|
690
+ if i % week_index[:modifier] == 0
691
+ week = OpeningHoursConverter::WeekIndex.week_from_index(index, year)
692
+ weeks_as_days << OpeningHoursConverter::WideInterval.new.day(week[:from].day, week[:from].month, week[:from].year,
693
+ week[:to].day, week[:to].month, week[:to].year)
694
+ end
695
+ i += 1
696
+ end
697
+ else
698
+ (week_index[:from]..week_index[:to]).map do |index|
699
+ week = OpeningHoursConverter::WeekIndex.week_from_index(index, year)
700
+ weeks_as_days << OpeningHoursConverter::WideInterval.new.day(week[:from].day, week[:from].month, week[:from].year,
701
+ week[:to].day, week[:to].month, week[:to].year)
702
+ end
703
+ end
704
+ end
705
+ end
706
+
707
+ weeks_as_days
708
+ end
709
+ def get_public_holidays_for_year(year = Time.now.year)
710
+ OpeningHoursConverter::PublicHoliday.ph_for_year(year).map do |holiday|
711
+ OpeningHoursConverter::WideInterval.new.day(holiday.day, holiday.month, holiday.year)
563
712
  end
564
713
  end
565
714
  end
@@ -82,7 +82,59 @@ module OpeningHoursConverter
82
82
  def self.build_day_array_from_dates(dates, get_iterator=false)
83
83
  years = {}
84
84
  dates.each do |date|
85
- if !date.wide_interval.start.nil? && !date.wide_interval.start[:year].nil?
85
+
86
+ if date.wide_interval.type == 'week'
87
+ if date.wide_interval.start.nil? || date.wide_interval.start[:year].nil?
88
+ date.wide_interval.indexes.each do |week_index|
89
+ if week_index.is_a? Integer
90
+ years["always"] ||= []
91
+ years["always"] << { start: { week: week_index }, end: { week: week_index } }
92
+ elsif week_index.is_a?(Hash) && week_index.key?(:modifier)
93
+ # week range with modifier
94
+ years["always"] ||= []
95
+ years["always"] << { start: { week: week_index[:from] }, end: { week: week_index[:to] }, modifier: week_index[:modifier] }
96
+ else
97
+ # week range
98
+ years["always"] ||= []
99
+ years["always"] << { start: { week: week_index[:from] }, end: { week: week_index[:to] } }
100
+ end
101
+ end
102
+ else
103
+ if date.wide_interval.end.nil? || date.wide_interval.end[:year].nil?
104
+ date.wide_interval.indexes.each do |week_index|
105
+ if week_index.is_a? Integer
106
+ years[date.wide_interval.start[:year]] ||= []
107
+ years[date.wide_interval.start[:year]] << { start: { week: week_index }, end: { week: week_index } }
108
+ elsif week_index.is_a?(Hash) && week_index.key?(:modifier)
109
+ # week range with modifier
110
+ years[date.wide_interval.start[:year]] ||= []
111
+ years[date.wide_interval.start[:year]] << { start: { week: week_index[:from] }, end: { week: week_index[:to] }, modifier: week_index[:modifier] }
112
+ else
113
+ # week range
114
+ years[date.wide_interval.start[:year]] ||= []
115
+ years[date.wide_interval.start[:year]] << { start: { week: week_index[:from] }, end: { week: week_index[:to] } }
116
+ end
117
+ end
118
+ else
119
+ date.wide_interval.start[:year].upto(date.wide_interval.end[:year]) do |year|
120
+ date.wide_interval.indexes.each do |week_index|
121
+ if week_index.is_a? Integer
122
+ years[year] ||= []
123
+ years[year] << { start: { week: week_index }, end: { week: week_index } }
124
+ elsif week_index.is_a?(Hash) && week_index.key?(:modifier)
125
+ # week range with modifier
126
+ years[year] ||= []
127
+ years[year] << { start: { week: week_index[:from] }, end: { week: week_index[:to] }, modifier: week_index[:modifier] }
128
+ else
129
+ # week range
130
+ years[year] ||= []
131
+ years[year] << { start: { week: week_index[:from] }, end: { week: week_index[:to] } }
132
+ end
133
+ end
134
+ end
135
+ end
136
+ end
137
+ elsif !date.wide_interval.start.nil? && !date.wide_interval.start[:year].nil?
86
138
  if date.wide_interval.end.nil? || date.wide_interval.end[:year].nil? || date.wide_interval.start[:year] == date.wide_interval.end[:year]
87
139
  if !years[date.wide_interval.start[:year]].nil?
88
140
  years = process_single_year(date.wide_interval, years)
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: opening_hours_converter
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.8.1
4
+ version: 1.9.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ziserman Martin
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-05-21 00:00:00.000000000 Z
11
+ date: 2019-05-29 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: json
@@ -79,8 +79,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
79
79
  - !ruby/object:Gem::Version
80
80
  version: '0'
81
81
  requirements: []
82
- rubyforge_project:
83
- rubygems_version: 2.7.3
82
+ rubygems_version: 3.0.3
84
83
  signing_key:
85
84
  specification_version: 4
86
85
  summary: Datetime range to openinghours, openinghours to datetime range