opening_hours_converter 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 3d01e4f3c1f4306964ee63ade1bb6e018722446a
4
+ data.tar.gz: 5671d033a5182245b46ff12838c2ccb11de8f7e5
5
+ SHA512:
6
+ metadata.gz: 99ec2ff1a1232f5ff42a6f0c015c4211fdf0a0a801b98c42d448e3b0828dfe0275e5e3246bd39403c716def6c3cbb241b35ad13a4a2114db592c12a0f6b38cb7
7
+ data.tar.gz: 4438647b1676e08b941159403631eefbc873e90970e24176006c30cb10406822b65a978e93d930fea8486c6b3c4b9f86ca40af42d5910484a633890a70ca9a4c
@@ -0,0 +1,22 @@
1
+ module OpeningHoursConverter
2
+ module Constants
3
+ DAYS = {
4
+ LUNDI: 0,
5
+ MARDI: 1,
6
+ MERCREDI: 2,
7
+ JEUDI: 3,
8
+ VENDREDI: 4,
9
+ SAMEDI: 5,
10
+ DIMANCHE: 6
11
+ }
12
+ OSM_DAYS = [ "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su" ]
13
+ IRL_DAYS = [ "Lundi", "Mardi", "Mercredi", "Jeudi", "Vendredi", "Samedi", "Dimanche" ]
14
+ OSM_MONTHS = [ "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" ]
15
+ IRL_MONTHS = [ "Janvier", "Fevrier", "Mars", "Avril", "Mai", "Juin", "Juillet", "Aout", "Septembre",
16
+ "Octobre", "Novembre", "Décembre" ]
17
+ MONTH_END_DAY = [ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 ]
18
+ MINUTES_MAX = 1440
19
+ DAYS_MAX = 6
20
+ YEAR_DAYS_MAX = 365
21
+ end
22
+ end
@@ -0,0 +1,48 @@
1
+ module OpeningHoursConverter
2
+ class DateRange
3
+ attr_accessor :wide_interval, :typical
4
+
5
+ def initialize(w=nil)
6
+ @wide_interval = nil
7
+ @typical = nil
8
+ update_range(w)
9
+ end
10
+
11
+ def defines_typical_day?
12
+ @typical.instance_of?(OpeningHoursConverter::Day)
13
+ end
14
+
15
+ def defines_typical_week?
16
+ @typical.instance_of?(OpeningHoursConverter::Week)
17
+ end
18
+
19
+ def update_range(wide)
20
+ @wide_interval = !wide.nil? ? wide : OpeningHoursConverter::WideInterval.new.always
21
+
22
+ if @typical.nil?
23
+ case @wide_interval.type
24
+ when "day"
25
+ if @wide_interval.end.nil?
26
+ @typical = OpeningHoursConverter::Day.new
27
+ else
28
+ @typical = OpeningHoursConverter::Week.new
29
+ end
30
+ when "week"
31
+ @typical = OpeningHoursConverter::Week.new
32
+ when "month"
33
+ @typical = OpeningHoursConverter::Week.new
34
+ when "always"
35
+ @typical = OpeningHoursConverter::Week.new
36
+ end
37
+ end
38
+ end
39
+
40
+ def has_same_typical?(date_range)
41
+ defines_typical_day? == date_range.defines_typical_day? && @typical.same_as?(date_range.typical)
42
+ end
43
+
44
+ def is_general_for?(date_range)
45
+ defines_typical_day? == date_range.defines_typical_day? && @wide_interval.contains?(date_range.wide_interval)
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,100 @@
1
+ require 'opening_hours_converter/constants'
2
+
3
+ module OpeningHoursConverter
4
+ class Day
5
+ include Constants
6
+ attr_accessor :intervals
7
+
8
+ def initialize
9
+ @intervals = []
10
+ end
11
+
12
+ def get_as_minute_array
13
+ minute_array = Array.new(MINUTES_MAX + 1, false)
14
+
15
+ @intervals.each do |interval|
16
+ if !interval.nil?
17
+ start_minute = nil
18
+ end_minute = nil
19
+
20
+ if interval.day_start == interval.day_end || interval.day_end == DAYS_MAX && interval.end == MINUTES_MAX
21
+ start_minute = interval.start
22
+ end_minute = interval.end
23
+ end
24
+
25
+ unless start_minute.nil? && end_minute.nil?
26
+ for minute in start_minute..end_minute
27
+ minute_array[minute] = true
28
+ end
29
+ else
30
+ raise "Invalid interval #{interval.inspect}"
31
+ end
32
+ end
33
+ end
34
+
35
+ minute_array
36
+ end
37
+
38
+ def get_intervals(clean=false)
39
+ if clean
40
+ minute_array = get_as_minute_array
41
+ intervals = []
42
+ minute_start = -1
43
+ minute_end = nil
44
+ minute_array.each_with_index do |minute, i|
45
+ if i == 0
46
+ if minute
47
+ minute_start = i
48
+ end
49
+ elsif i == minute_array.length - 1
50
+ if minute
51
+ intervals << OpeningHoursConverter::Interval.new(0, minute_start, 0, i - 1)
52
+ minute_start = -1
53
+ end
54
+ else
55
+ if minute && minute_start < 0
56
+ minute_start = i
57
+ elsif !minute && minute_start >= 0
58
+ intervals << OpeningHoursConverter::Interval.new(0, minute_start, 0, i - 1)
59
+ minute_start = -1
60
+ end
61
+ end
62
+ end
63
+ intervals
64
+ else
65
+ @intervals
66
+ end
67
+ end
68
+
69
+ def add_interval(interval)
70
+ @intervals << interval
71
+ return @intervals.length - 1
72
+ end
73
+
74
+ def edit_interval(id, interval)
75
+ @intervals[id] = interval
76
+ end
77
+
78
+ def remove_interval(id)
79
+ @intervals[id] = nil
80
+ end
81
+
82
+ def clear_intervals
83
+ @intervals = []
84
+ end
85
+
86
+ def copy_intervals(intervals)
87
+ @intervals = []
88
+ intervals.each do |interval|
89
+ if !interval.nil? && interval.day_start == 0 && interval.day_end == 0
90
+ @intervals << interval.dup
91
+ end
92
+ end
93
+ @intervals = get_intervals(true)
94
+ end
95
+
96
+ def same_as?(day)
97
+ day.get_as_minute_array == get_as_minute_array
98
+ end
99
+ end
100
+ end
@@ -0,0 +1,20 @@
1
+ require 'opening_hours_converter/constants'
2
+
3
+ module OpeningHoursConverter
4
+ class Interval
5
+ include Constants
6
+ attr_accessor :day_start, :day_end, :start, :end
7
+
8
+ def initialize(day_start, min_start, day_end=0, min_end=0)
9
+ @day_start = day_start
10
+ @day_end = day_end
11
+ @start = min_start
12
+ @end = min_end
13
+
14
+ if @day_end == 0 && @end == 0
15
+ @day_end = DAYS_MAX
16
+ @end = MINUTES_MAX
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,368 @@
1
+ require 'opening_hours_converter/constants'
2
+
3
+ module OpeningHoursConverter
4
+ class OpeningHoursBuilder
5
+ include Constants
6
+ def build(date_ranges)
7
+ rules = []
8
+
9
+ oh_rules = nil
10
+ oh_rule_added = nil
11
+ range_general = nil
12
+ range_general_for = nil
13
+
14
+ date_ranges.each_with_index do |date_range, date_range_index|
15
+ if !date_range.nil?
16
+ range_general = nil
17
+ range_general_for = nil
18
+ range_general_id = date_range_index - 1
19
+ while range_general_id >= 0 && range_general.nil?
20
+ if !date_range.nil?
21
+ general_for = date_ranges[range_general_id].is_general_for?(date_range)
22
+ if date_ranges[range_general_id].has_same_typical?(date_range) && (date_ranges[range_general_id].wide_interval.equals(date_range.wide_interval) || general_for)
23
+ range_general = range_general_id
24
+ elsif general_for && date_ranges[range_general_id].defines_typical_week? && date_range.defines_typical_week?
25
+ range_general_for = range_general_id
26
+ end
27
+ end
28
+ range_general_id -= 1
29
+ end
30
+
31
+ if date_range_index == 0 || range_general.nil?
32
+ if date_range.defines_typical_week?
33
+ if !range_general_for.nil?
34
+ oh_rules = build_week_diff(date_range, date_ranges[range_general_for])
35
+ else
36
+ oh_rules = build_week(date_range)
37
+ end
38
+ else
39
+ oh_rules = build_day(date_range)
40
+ end
41
+ end
42
+
43
+ oh_rule_index = 0
44
+
45
+ while oh_rule_index < oh_rules.length
46
+ oh_rule = oh_rules[oh_rule_index]
47
+ oh_rule_added = false
48
+ rule_index = 0
49
+
50
+ while !oh_rule_added && rule_index < rules.length
51
+ if rules[rule_index].same_time?(oh_rule)
52
+ begin
53
+ for date_id in 0...oh_rule.date.length
54
+ rules[rule_index].add_date(oh_rule.date[date_id])
55
+ end
56
+ oh_rule_added = true
57
+ rescue Exception => e
58
+ puts e
59
+ # if(
60
+ # ohrule.getDate()[0].getWideType() == "holiday"
61
+ # && ohrule.getDate()[0].getWideValue() == "PH"
62
+ # && rules[ruleId].getDate()[0].getWideType() == "always"
63
+ # ) {
64
+ # rules[ruleId].addPhOpeningHoursConverter::Weekday();
65
+ # ohruleAdded = true;
66
+ # }
67
+ # else if(
68
+ # rules[ruleId].getDate()[0].getWideType() == "holiday"
69
+ # && rules[ruleId].getDate()[0].getWideValue() == "PH"
70
+ # && ohrule.getDate()[0].getWideType() == "always"
71
+ # ) {
72
+ # ohrule.addPhOpeningHoursConverter::Weekday();
73
+ # rules[ruleId] = ohrule;
74
+ # ohruleAdded = true;
75
+ # }
76
+ # else {
77
+ # ruleId++;
78
+ # }
79
+ rule_index += 1
80
+ end
81
+ else
82
+ rule_index+=1
83
+ end
84
+
85
+ end
86
+
87
+ if !oh_rule_added
88
+ rules << oh_rule
89
+ end
90
+
91
+ if oh_rule_index == oh_rules.length - 1 && oh_rule.has_overwritten_weekday?
92
+ oh_rule_over = OpeningHoursConverter::OpeningHoursRule.new
93
+
94
+ oh_rule.date.each do |date|
95
+ oh_rule_over.add_date(OpeningHoursConverter::OpeningHoursDate.new(date.wide, date.wide_type, date.weekdays_over))
96
+ end
97
+ oh_rule_over.add_time(OpeningHoursConverter::OpeningHoursTime.new)
98
+ oh_rules << oh_rule_over
99
+ oh_rule_index += 1
100
+ else
101
+ oh_rule_index += 1
102
+ end
103
+ end
104
+ end
105
+ end
106
+
107
+
108
+ result = ""
109
+ rules.each_with_index do |rule, rule_index|
110
+ if rule_index > 0
111
+ result += "; "
112
+ end
113
+ result += rule.get
114
+ end
115
+
116
+ return result
117
+ end
118
+
119
+ def build_day(date_range)
120
+ intervals = date_range.typical.get_intervals(true)
121
+
122
+ rule = OpeningHoursConverter::OpeningHoursRule.new
123
+ date = OpeningHoursConverter::OpeningHoursDate.new(date_range.wide_interval.get_time_selector, date_range.wide_interval.type, [-1])
124
+ rule.add_date(date)
125
+
126
+ intervals.each do |interval|
127
+ if !interval.nil?
128
+ rule.add_time(OpeningHoursConverter::OpeningHoursTime.new(interval.start, interval.end))
129
+ end
130
+ end
131
+
132
+ return [ rule ]
133
+ end
134
+
135
+ def build_week(date_range)
136
+ result = []
137
+ intervals = date_range.typical.get_intervals(true)
138
+ time_intervals = create_time_intervals(date_range.wide_interval.get_time_selector, date_range.wide_interval.type, intervals)
139
+
140
+ monday0 = time_intervals[0]
141
+ sunday24 = time_intervals[1]
142
+ days = time_intervals[2]
143
+
144
+ days = night_monday_sunday(days, monday0, sunday24)
145
+
146
+
147
+ days_status = Array.new(OSM_DAYS.length, 0)
148
+
149
+ days.each_with_index do |day, index|
150
+ if day.is_off? && days_status[index] == 0
151
+ days_status[index] = 8
152
+ elsif day.is_off? && days_status[index] < 0 && days_status[index] > -8
153
+ days_status[index] = -8
154
+ merged = false
155
+ md_off = 0
156
+ while !merged && md_off < index
157
+ if days[md_off].is_off?
158
+ days[md_off].add_weekday(index)
159
+ merged = true
160
+ else
161
+ md_off += 1
162
+ end
163
+ if !merged
164
+ result << days[index]
165
+ end
166
+ end
167
+ elsif days_status[index] <= 0 && days_status[index] > -8
168
+ days_status[index] = index + 1
169
+ last_same_day = index
170
+ same_day_count = 1
171
+
172
+ for j in (index+1)...days.length do
173
+ if day.same_time?(days[j])
174
+ days_status[j] = index + 1
175
+ day.add_weekday(j)
176
+ last_same_day = j
177
+ same_day_count += 1
178
+ end
179
+ end
180
+ if same_day_count == 1
181
+ result << day
182
+ elsif same_day_count == 2
183
+ day.add_weekday(last_same_day)
184
+ result << day
185
+ elsif same_day_count > 2
186
+ for j in (index+1)...last_same_day do
187
+ if days_status[j] == 0
188
+ days_status[j] = -index -1
189
+ day.add_overwritten_weekday(j)
190
+ end
191
+ end
192
+ day.add_weekday(last_same_day)
193
+ result << day
194
+ end
195
+ end
196
+ end
197
+ result = merge_days(result)
198
+
199
+ return result
200
+ end
201
+
202
+ def build_week_diff(date_range, general_date_range)
203
+ intervals = date_range.typical.get_intervals_diff(general_date_range.typical)
204
+
205
+ time_intervals = create_time_intervals(
206
+ date_range.wide_interval.get_time_selector,
207
+ date_range.wide_interval.type,
208
+ intervals[:open])
209
+ monday0 = time_intervals[0]
210
+ sunday24 = time_intervals[1]
211
+ days = time_intervals[2]
212
+ intervals[:closed].each do |interval|
213
+ for i in interval.day_start..interval.day_end do
214
+ days[i].add_time(OpeningHoursConverter::OpeningHoursTime.new)
215
+ end
216
+ end
217
+
218
+ days = night_monday_sunday(days, monday0, sunday24)
219
+
220
+ days_status = Array.new(OSM_DAYS.length, 0)
221
+ result = []
222
+
223
+ days.each_with_index do |day, index|
224
+ if day.is_off? && day.time.length == 1
225
+ days_status[index] = -8
226
+ merged = false
227
+ md_off = 0
228
+
229
+ while !merged && md_off < index
230
+ if days[md_off].is_off? && days[md_off].time.length == 1
231
+ days[md_off].add_weekday(index)
232
+ merged = true
233
+ else
234
+ md_off += 1
235
+ end
236
+ end
237
+
238
+ if !merged
239
+ result << day
240
+ end
241
+ elsif day.is_off? && day.time.length == 0
242
+ days_status[index] = 8
243
+ elsif days_status[index] <= 0 && days_status[index] > -8
244
+ days_status[index] = index + 1
245
+ same_day_count = 1
246
+ last_same_day = 1
247
+ result << day
248
+
249
+ for j in (index + 1)...days.length do
250
+ if day.same_time?(days[j])
251
+ days_status[j] = index + 1
252
+ day.add_weekday(j)
253
+ last_same_day = j
254
+ same_day_count += 1
255
+ end
256
+ end
257
+
258
+ if same_day_count == 1
259
+ result << day
260
+ elsif same_day_count == 2
261
+ day.add_weekday(last_same_day)
262
+ result << day
263
+ elsif same_day_count > 2
264
+ for j in (index + 1)...last_same_day do
265
+ if days_status[j] == 0
266
+ days_status[j] = -index - 1
267
+ if days[j].time.length > 0
268
+ day.add_overwritten_weekday(j)
269
+ end
270
+ end
271
+ end
272
+ day.add_weekday(last_same_day)
273
+ result << day
274
+ end
275
+
276
+ end
277
+ end
278
+ result = merge_days(result)
279
+ return result
280
+ end
281
+
282
+ def merge_days(rules)
283
+ return rules if rules.length == 0
284
+ result = []
285
+ result << rules[0]
286
+ dm = 0
287
+
288
+ for d in 1...rules.length do
289
+ date_merged = false
290
+ dm = 0
291
+ while !date_merged && dm < d
292
+ if rules[dm].same_time?(rules[d])
293
+ wds = rules[d].date[0].weekdays
294
+ wds.each do |wd|
295
+ rules[dm].add_weekday(wd)
296
+ end
297
+ date_merged = true
298
+ end
299
+ dm += 1
300
+ end
301
+ if !date_merged
302
+ result << rules[d]
303
+ end
304
+ end
305
+
306
+ return result
307
+ end
308
+
309
+ def create_time_intervals(time_selector, type, intervals)
310
+ monday0 = -1
311
+ sunday24 = -1
312
+
313
+ days = []
314
+ for i in 0...7 do
315
+ days << OpeningHoursConverter::OpeningHoursRule.new
316
+ days[i].add_date(OpeningHoursConverter::OpeningHoursDate.new(time_selector, type, [ i ]))
317
+ end
318
+
319
+ intervals.each do |interval|
320
+ if !interval.nil?
321
+ if interval.day_start == DAYS_MAX && interval.day_end == DAYS_MAX && interval.end == MINUTES_MAX
322
+ sunday24 = interval.start
323
+ end
324
+ if interval.day_start == 0 && interval.day_end == 0 && interval.start == 0
325
+ monday0 = interval.end
326
+ end
327
+ begin
328
+ if interval.day_start == interval.day_end
329
+ days[interval.day_start].add_time(OpeningHoursConverter::OpeningHoursTime.new(interval.start, interval.end))
330
+ elsif interval.day_end - interval.day_start == 1
331
+ if interval.start > interval.end
332
+ days[interval.day_start].add_time(OpeningHoursConverter::OpeningHoursTime.new(interval.start, interval.end))
333
+ else
334
+ days[interval.day_start].add_time(OpeningHoursConverter::OpeningHoursTime.new(interval.start, MINUTES_MAX))
335
+ days[interval.day_end].add_time(OpeningHoursConverter::OpeningHoursTime.new(0, interval.end))
336
+ end
337
+ else
338
+ for j in interval.day_start..interval.day_end do
339
+ if j == interval.day_start
340
+ days[j].add_time(OpeningHoursConverter::OpeningHoursTime.new(interval.start, MINUTES_MAX))
341
+ elsif j == interval.day_end
342
+ days[j].add_time(OpeningHoursConverter::OpeningHoursTime.new(0, interval.end))
343
+ else
344
+ days[j].add_time(OpeningHoursConverter::OpeningHoursTime.new(0, MINUTES_MAX))
345
+ end
346
+ end
347
+ end
348
+ rescue Exception => e
349
+ puts e
350
+ end
351
+ end
352
+ end
353
+
354
+ return [ monday0, sunday24, days ]
355
+ end
356
+
357
+ def night_monday_sunday(days, monday0, sunday24)
358
+ if monday0 >= 0 && sunday24 >= 0 && monday0 < sunday24
359
+ days[0].time.sort! { |a, b| a.start <=> b.start }
360
+ days[6].time.sort! { |a, b| a.start <=> b.start }
361
+
362
+ days[6].time[days[6].time.length - 1] = OpeningHoursConverter::OpeningHoursTime.new(sunday24, monday0)
363
+ days[0].time.shift
364
+ end
365
+ return days
366
+ end
367
+ end
368
+ end
@@ -0,0 +1,126 @@
1
+ require 'opening_hours_converter/constants'
2
+
3
+ module OpeningHoursConverter
4
+ class OpeningHoursDate
5
+ include Constants
6
+ attr_accessor :wide_type, :wide, :weekdays, :weekdays_over
7
+
8
+ def initialize(wide, wide_type, weekdays)
9
+ if wide.nil? || wide_type.nil? || weekdays.nil?
10
+ raise ArgumentError
11
+ end
12
+
13
+ @wide = wide
14
+ @wide_type = wide_type
15
+ @weekdays = weekdays.sort
16
+ @weekdays_over = []
17
+ end
18
+
19
+ def get_weekdays
20
+
21
+ result = ""
22
+ wd = @weekdays.concat(@weekdays_over).sort.uniq
23
+
24
+ if wd.length > 0 && wd.include?(6) && wd.include?(0) && (wd.include?(5) || wd.include?(1))
25
+ start_we = 6
26
+ i = wd.length - 2
27
+ stop_looking = false
28
+
29
+ while !stop_looking && i >= 0
30
+ if wd[i] == wd[i+1] - 1
31
+ start_we = wd[i]
32
+ i -= 1
33
+ else
34
+ stop_looking = true
35
+ end
36
+ end
37
+
38
+ i = 1
39
+ stop_looking = false
40
+ end_we = 0
41
+
42
+ while !stop_looking && i < wd.length
43
+ if wd[i-1] == wd[i] - 1
44
+ end_we = wd[i]
45
+ i += 1
46
+ else
47
+ stop_looking = true
48
+ end
49
+ end
50
+
51
+ length = 7 - start_we + end_we + 1
52
+
53
+ if length >= 3 && start_we > end_we
54
+ if result.length > 0
55
+ result += ","
56
+ end
57
+ result += "#{OSM_DAYS[start_we]}-#{OSM_DAYS[end_we]}"
58
+
59
+ j=0
60
+ while j < wd.length
61
+ if wd[j] <= end_we || wd[j] >= start_we
62
+ wd.slice!(j, 1)
63
+ else
64
+ j+=1
65
+ end
66
+ end
67
+ end
68
+ end
69
+
70
+ if wd.length > 1 || (wd.length == 1 && wd[0] != -1)
71
+ result += result.length > 0 ? ",#{OSM_DAYS[wd[0]]}" : OSM_DAYS[wd[0]]
72
+ first_in_row = wd[0]
73
+ for i in 1...wd.length
74
+ if wd[i-1] != wd[i] - 1
75
+ if first_in_row != wd[i-1]
76
+ if wd[i-1] - first_in_row == 1
77
+ result += ",#{OSM_DAYS[wd[i-1]]}"
78
+ else
79
+ result += "-#{OSM_DAYS[wd[i-1]]}"
80
+ end
81
+ end
82
+ result += ",#{OSM_DAYS[wd[i]]}"
83
+ first_in_row = wd[i]
84
+ elsif i == wd.length - 1
85
+ if wd[i] - first_in_row == 1
86
+ result += ",#{OSM_DAYS[wd[i]]}"
87
+ else
88
+ result += "-#{OSM_DAYS[wd[i]]}"
89
+ end
90
+ end
91
+ end
92
+ end
93
+
94
+ if result == "Mo-Su"
95
+ result = ""
96
+ end
97
+ return result
98
+ end
99
+
100
+ def add_weekday(weekday)
101
+ if !@weekdays.include?(weekday) && !@weekdays_over.include?(weekday)
102
+ @weekdays << weekday
103
+ @weekdays.sort!
104
+ end
105
+ end
106
+
107
+ def add_overwritten_weekday(weekday)
108
+ unless @weekdays_over.include?(weekday) && @weekdays_over.include?(weekday)
109
+ @weekdays_over << weekday
110
+ @weekdays_over.sort!
111
+ end
112
+ end
113
+
114
+ def same_kind_as?(date)
115
+ @wide_type == date.wide_type && date.same_weekdays?(@weekdays)
116
+ end
117
+
118
+ def same_weekdays?(weekdays)
119
+ weekdays == @weekdays
120
+ end
121
+
122
+ def equals(o)
123
+ o.instance_of?(OpeningHoursConverter::OpeningHoursDate) && @wide_type == o.wide_type && @wide == o.wide && o.same_weekdays?(@weekdays)
124
+ end
125
+ end
126
+ end