opening_hours_converter 0.0.2

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.
@@ -0,0 +1,519 @@
1
+ require 'opening_hours_converter/constants'
2
+
3
+ module OpeningHoursConverter
4
+ class OpeningHoursParser
5
+ include Constants
6
+ attr_accessor :RGX_RULE_MODIFIER, :RGX_WEEK_KEY, :RGX_WEEK_VAL, :RGX_MONTH, :RGX_MONTHDAY, :RGX_TIME, :RGX_WEEKDAY, :RGX_HOLIDAY, :RGX_WD
7
+ def initialize
8
+ @RGX_RULE_MODIFIER = /^(open|closed|off)$/i
9
+ @RGX_WEEK_KEY = /^week$/
10
+ @RGX_WEEK_VAL = /^([01234]?[0-9]|5[0123])(\-([01234]?[0-9]|5[0123]))?(,([01234]?[0-9]|5[0123])(\-([01234]?[0-9]|5[0123]))?)*\:?$/
11
+ @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))?\:?$/
12
+ @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]))?\:?$/
13
+ @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))$/
14
+ @RGX_WEEKDAY = /^(((Mo|Tu|We|Th|Fr|Sa|Su)(\-(Mo|Tu|We|Th|Fr|Sa|Su))?)|(PH|SH|easter))(,(((Mo|Tu|We|Th|Fr|Sa|Su)(\-(Mo|Tu|We|Th|Fr|Sa|Su))?)|(PH|SH|easter)))*$/
15
+ @RGX_HOLIDAY = /^(PH|SH|easter)$/
16
+ @RGX_WD = /^(Mo|Tu|We|Th|Fr|Sa|Su)(\-(Mo|Tu|We|Th|Fr|Sa|Su))?$/
17
+ @RGX_YEAR = /^(\d{4})(\-(\d{4}))?$/
18
+ @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]))?\:?$/
19
+ @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)))?\:?$/
20
+ end
21
+
22
+ def parse(oh)
23
+ result = []
24
+ blocks = oh.split(';')
25
+
26
+ rule_modifier = nil
27
+ time_selector = nil
28
+ weekday_selector = nil
29
+ wide_range_selector = nil
30
+ month_selector = nil
31
+
32
+ times = nil
33
+ weekdays = nil
34
+ weeks = nil
35
+ months = nil
36
+ years = nil
37
+
38
+ single_month = nil
39
+ month_from = nil
40
+ month_to = nil
41
+
42
+ single_year = nil
43
+ year_from = nil
44
+ year_to = nil
45
+
46
+ single_year = nil
47
+ year_from = nil
48
+ year_to = nil
49
+
50
+ date_ranges = nil
51
+ date_range = nil
52
+ dr_obj = nil
53
+ res_dr_id = nil
54
+
55
+ blocks.each do |block|
56
+ block.strip!
57
+ next if block.length == 0
58
+
59
+ tokens = tokenize(block)
60
+ current_token = tokens.length - 1
61
+
62
+ # get state
63
+ if current_token >= 0 && is_rule_modifier?(tokens[current_token])
64
+ rule_modifier = tokens[current_token].downcase
65
+ current_token -= 1
66
+ end
67
+
68
+ times = []
69
+ if current_token >= 0 && is_time?(tokens[current_token])
70
+ time_selector = tokens[current_token]
71
+ times = get_times(time_selector)
72
+ current_token -= 1
73
+ end
74
+
75
+ # get weekdays selector
76
+ weekdays = []
77
+ if time_selector == "24/7"
78
+ weekdays << {from: 0, to: 6}
79
+ elsif current_token >= 0 && is_weekday?(tokens[current_token])
80
+ weekday_selector = tokens[current_token]
81
+ weekdays = get_weekdays(weekday_selector)
82
+ current_token -= 1
83
+ end
84
+
85
+ # years = []
86
+ # if current_token >= 0 && is_year?(tokens[current_token])
87
+ # year_selector = tokens[current_token]
88
+ # year_selector = year_selector.split(',')
89
+ # year_selector.each do |y|
90
+ # single_year = y.gsub(/\:$/, '').split('-')
91
+ # year_from = single_year[0]
92
+ # if single_year.length > 1
93
+ # year_to = single_year[1]
94
+ # else
95
+ # year_to = year_from
96
+ # end
97
+
98
+ # years << {from: year_from, to: year_to}
99
+ # end
100
+ # current_token -= 1
101
+ # end
102
+
103
+ months = []
104
+ years = []
105
+ if current_token >= 0
106
+
107
+ wide_range_selector = tokens[0]
108
+ for i in 1..current_token
109
+ wide_range_selector += " #{tokens[i]}"
110
+ end
111
+ if wide_range_selector.length > 0
112
+ wide_range_selector = wide_range_selector.strip
113
+ wide_range_selector = wide_range_selector.split(',')
114
+ wide_range_selector.each do |wrs|
115
+ if !(@RGX_YEAR_MONTH_DAY =~ wrs).nil?
116
+ years << get_year_month_day(wrs)
117
+ elsif !(@RGX_YEAR_MONTH =~ wrs).nil?
118
+ years << get_year_month(wrs)
119
+ elsif !(@RGX_MONTHDAY =~ wrs).nil?
120
+ months << get_month_day(wrs)
121
+ elsif !(@RGX_MONTH =~ wrs).nil?
122
+ months << get_month(wrs)
123
+ elsif !(@RGX_YEAR =~ wrs).nil?
124
+
125
+ years << {from: year_from, to: year_to}
126
+ else
127
+ raise ArgumentError, "Unsupported selector #{wrs}"
128
+ end
129
+ end
130
+ end
131
+ end
132
+
133
+ if current_token == tokens.length - 1
134
+ raise ArgumentError, "Unreadable string"
135
+ end
136
+ puts "months : #{months}"
137
+ puts "weekdays : #{weekdays}"
138
+ puts "times : #{times}"
139
+ puts "years : #{years}"
140
+ puts "rule_modifier : #{rule_modifier}"
141
+
142
+ date_ranges = []
143
+
144
+ if months.length > 0
145
+ months.each do |month|
146
+ if !month[:from_day].nil?
147
+ if !month[:to_day].nil?
148
+ date_range = OpeningHoursConverter::WideInterval.new.day(month[:from_day][:day], month[:from_day][:month], nil, month[:to_day][:day], month[:to_day][:month], nil)
149
+ else
150
+ date_range = OpeningHoursConverter::WideInterval.new.day(month[:from_day][:day], month[:from_day][:month])
151
+ end
152
+ date_ranges << date_range
153
+ else
154
+ if !month[:to].nil?
155
+ date_range = OpeningHoursConverter::WideInterval.new.month(month[:from], nil, month[:to])
156
+ else
157
+ date_range = OpeningHoursConverter::WideInterval.new.month(month[:from])
158
+ end
159
+ date_ranges << date_range
160
+ end
161
+ end
162
+ elsif years.length > 0
163
+ years.each do |year|
164
+ # binding.pry
165
+ if !year[:to].nil?
166
+ if !year[:from_day].nil?
167
+ date_range = OpeningHoursConverter::WideInterval.new.day(year[:from_day][:day], year[:from_day][:month], year[:from_day][:year],
168
+ year[:to_day][:day], year[:to_day][:month], year[:to_day][:year])
169
+ elsif !year[:from_month].nil?
170
+ date_range = OpeningHoursConverter::WideInterval.new.month(year[:from_month][:month], year[:from_month][:year],
171
+ year[:to_month][:month], year[:to_month][:year])
172
+ else
173
+ date_range = OpeningHoursConverter::WideInterval.new.year(year[:from], year[:to])
174
+ end
175
+ else
176
+ if !year[:from_month].nil?
177
+ date_range = OpeningHoursConverter::WideInterval.new.month(year[:from_month][:month], year[:from_month][:year])
178
+ elsif !year[:from_day].nil?
179
+ date_range = OpeningHoursConverter::WideInterval.new.day(year[:from_day][:day], year[:from_day][:month], year[:from_day][:year])
180
+ else
181
+ date_range = OpeningHoursConverter::WideInterval.new.year(year[:from])
182
+ end
183
+ end
184
+ date_ranges << date_range
185
+ end
186
+ else
187
+ date_ranges << OpeningHoursConverter::WideInterval.new.always
188
+ end
189
+
190
+ if weekdays.length == 0
191
+ weekdays << {from: 0, to: OSM_DAYS.length - 1}
192
+ end
193
+
194
+ if times.length == 0
195
+ times << {from: 0, to: 24*60}
196
+ end
197
+
198
+ # pasur
199
+ date_ranges.each do |dr|
200
+ found_date_range = false
201
+ res_dr_id = 0
202
+
203
+ while res_dr_id < result.length && !found_date_range
204
+ if result[res_dr_id].wide_interval.equals(dr)
205
+ found_date_range = true
206
+ else
207
+ res_dr_id += 1
208
+ end
209
+ end
210
+
211
+ if found_date_range
212
+ dr_obj = result[res_dr_id]
213
+ else
214
+ dr_obj = OpeningHoursConverter::DateRange.new(dr)
215
+
216
+ general = -1
217
+ for res_dr_id in 0...result.length
218
+ if result[res_dr_id].is_general_for?(OpeningHoursConverter::DateRange.new(dr))
219
+ general = res_dr_id
220
+ end
221
+ end
222
+ if general >= 0
223
+ dr_obj.typical.copy_intervals(result[general].typical.intervals)
224
+ end
225
+ result << dr_obj
226
+ end
227
+
228
+ for wd_id in 0...weekdays.length
229
+ if weekdays[wd_id][:from] <= weekdays[wd_id][:to]
230
+ for wd_rm in weekdays[wd_id][:from]..weekdays[wd_id][:to]
231
+ if dr_obj.defines_typical_week?
232
+ dr_obj.typical.remove_intervals_during_day(wd_rm)
233
+ else
234
+ dr_obj.typical.clear_intervals
235
+ end
236
+ end
237
+ else
238
+ for wd_rm in weekdays[wd_id][:from]..6
239
+ if dr_obj.defines_typical_week?
240
+ dr_obj.typical.remove_intervals_during_day(wd_rm)
241
+ else
242
+ dr_obj.typical.clear_intervals
243
+ end
244
+ end
245
+ for wd_rm in 0..weekdays[wd_id][:to]
246
+ if dr_obj.defines_typical_week?
247
+ dr_obj.typical.remove_intervals_during_day(wd_rm)
248
+ else
249
+ dr_obj.typical.clear_intervals
250
+ end
251
+ end
252
+ end
253
+
254
+ for t_id in 0...times.length
255
+ if rule_modifier == "closed" || rule_modifier == "off"
256
+ remove_interval(dr_obj.typical, weekdays[wd_id], times[t_id])
257
+ else
258
+ add_interval(dr_obj.typical, weekdays[wd_id], times[t_id])
259
+ end
260
+ end
261
+ end
262
+ end
263
+ end
264
+ return result
265
+ end
266
+
267
+ def get_year(wrs)
268
+ single_year = wrs.gsub(/\:$/, '').split('-')
269
+ year_from = single_year[0].to_i
270
+ if year_from < 1
271
+ raise ArgumentError, "Invalid year : #{single_year[0]}"
272
+ end
273
+
274
+ if single_year.length > 1
275
+ year_to = single_year[1].to_i
276
+ if year_to < 1
277
+ raise ArgumentError, "Invalid year : #{single_year[1]}"
278
+ end
279
+ else
280
+ year_to = nil
281
+ end
282
+ { from: year_from, to: year_to }
283
+ end
284
+
285
+ def get_month(wrs)
286
+ single_month = wrs.gsub(/\:$/, '').split('-')
287
+ month_from = OSM_MONTHS.find_index(single_month[0]) + 1
288
+ if month_from < 1
289
+ raise ArgumentError, "Invalid month : #{single_month[0]}"
290
+ end
291
+
292
+ if single_month.length > 1
293
+ month_to = OSM_MONTHS.find_index(single_month[1]) + 1
294
+ if month_to < 1
295
+ raise ArgumentError, "Invalid month : #{single_month[1]}"
296
+ end
297
+ else
298
+ month_to = month_from
299
+ end
300
+ { from: month_from, to: month_to }
301
+ end
302
+
303
+ def get_month_day(wrs)
304
+ single_month = wrs.gsub(/\:$/, '').split('-')
305
+
306
+ month_from = single_month[0].split(' ')
307
+ month_from = { day: month_from[1].to_i, month: OSM_MONTHS.find_index(month_from[0]) + 1 }
308
+ if month_from[:month] < 1
309
+ raise ArgumentError, "Invalid month : #{month_from.inspect}"
310
+ end
311
+
312
+ if single_month.length > 1
313
+ month_to = single_month[1].split(' ')
314
+ month_to = { day: month_to[1].to_i, month: OSM_MONTHS.find_index(month_to[0]) + 1 }
315
+ if month_to[:month] < 1
316
+ raise ArgumentError, "Invalid month : #{month_to.inspect}"
317
+ end
318
+ else
319
+ month_to = nil
320
+ end
321
+ { from_day: month_from, to_day: month_to }
322
+ end
323
+
324
+ def get_year_month(wrs)
325
+ single_year_month = wrs.gsub(/\:$/, '').split('-')
326
+ year_month_from = single_year_month[0].split(' ')
327
+ year_month_from = { month: OSM_MONTHS.find_index(year_month_from[1]) + 1, year: year_month_from[0].to_i }
328
+ if year_month_from.length < 1
329
+ raise ArgumentError, "Invalid year_month : #{year_month_from.inspect}"
330
+ end
331
+ if single_year_month.length > 1
332
+ year_month_to = single_year_month[1].split(' ')
333
+ if year_month_to.length == 2
334
+ year_month_to = { month: OSM_MONTHS.find_index(year_month_to[1]) + 1, year: year_month_to[0].to_i }
335
+ elsif year_month_to.length == 1
336
+ year_month_to = { month: OSM_MONTHS.find_index(year_month_to[1]) + 1, year: year_month_from[:year] }
337
+ end
338
+ if year_month_to.length < 1
339
+ raise ArgumentError, "Invalid year_month : #{year_month_to.inspect}"
340
+ end
341
+ else
342
+ year_month_to = nil
343
+ end
344
+ { from_month: year_month_from, to_month: year_month_to }
345
+ end
346
+
347
+ def get_year_month_day(wrs)
348
+ single_year_month_day = wrs.gsub(/\:$/, '').split('-')
349
+ year_month_day_from = single_year_month_day[0].split(' ')
350
+ year_month_day_from = { day: year_month_day_from[2].to_i,
351
+ month: OSM_MONTHS.find_index(year_month_day_from[1]) + 1,
352
+ year: year_month_day_from[0].to_i }
353
+ if year_month_day_from.length < 1
354
+ raise ArgumentError, "Invalid year_month_day : #{year_month_day_from.inspect}"
355
+ end
356
+ if single_year_month_day.length > 1
357
+ year_month_day_to = single_year_month_day[1].split(' ')
358
+ if year_month_day_to.length == 3
359
+ year_month_day_to = { day: year_month_day_to[2].to_i,
360
+ month: OSM_MONTHS.find_index(year_month_day_to[1]) + 1,
361
+ year: year_month_day_to[0].to_i }
362
+ elsif year_month_day_to.length == 2
363
+ year_month_day_to = { day: year_month_day_to[1].to_i,
364
+ month: OSM_MONTHS.find_index(year_month_day_to[0]) + 1,
365
+ year: year_month_day_from[:year] }
366
+ elsif year_month_day_to.length == 1
367
+ year_month_day_to = { day: year_month_day_to[0].to_i,
368
+ month: year_month_day_from[:month],
369
+ year: year_month_day_from[:year] }
370
+ end
371
+ if year_month_day_to.length < 1
372
+ raise ArgumentError, "Invalid year_month_day : #{year_month_day_to.inspect}"
373
+ end
374
+ else
375
+ year_month_day_to = nil
376
+ end
377
+
378
+ { from_day: year_month_day_from, to_day: year_month_day_to }
379
+ end
380
+
381
+ def get_times(time_selector)
382
+ times = []
383
+ from = nil
384
+ to = nil
385
+ if time_selector == "24/7"
386
+ times << {from: 0, to: 24*60}
387
+ else
388
+ time_selector = time_selector.split(',')
389
+ time_selector.each do |ts|
390
+ single_time = ts.split('-')
391
+ from = as_minutes(single_time[0])
392
+ if single_time.length > 1
393
+ to = as_minutes(single_time[1])
394
+ else
395
+ to = from
396
+ end
397
+ times << {from: from, to: to}
398
+ end
399
+ end
400
+ times
401
+ end
402
+
403
+ def get_weekdays(weekday_selector)
404
+ weekdays = []
405
+ wd_from = nil
406
+ wd_to = nil
407
+
408
+ weekday_selector = weekday_selector.split(',')
409
+ weekday_selector.each do |wd|
410
+ if !(@RGX_HOLIDAY =~ wd).nil?
411
+ elsif !(@RGX_WD =~ wd).nil?
412
+ single_weekday = wd.split('-')
413
+ wd_from = OSM_DAYS.find_index(single_weekday[0])
414
+ if single_weekday.length > 1
415
+ wd_to = OSM_DAYS.find_index(single_weekday[1])
416
+ else
417
+ wd_to = wd_from
418
+ end
419
+
420
+ weekdays << {from: wd_from, to: wd_to}
421
+ else
422
+ raise ArgumentError, "Invalid weekday interval : #{wd}"
423
+ end
424
+ end
425
+
426
+ weekdays
427
+ end
428
+
429
+ def remove_interval(typical, weekdays, times)
430
+ if weekdays[:from] <= weekdays[:to]
431
+ for wd in weekdays[:from]..weekdays[:to]
432
+ typical.remove_intervals_during_day(wd)
433
+ end
434
+ else
435
+ for wd in weekdays[:from]..6
436
+ typical.remove_intervals_during_day(wd)
437
+ end
438
+ for wd in 0..weekdays[:from]
439
+ typical.remove_intervals_during_day(wd)
440
+ end
441
+ end
442
+ end
443
+
444
+ def remove_interval_wd(typical, times, wd)
445
+ if times[:to] >= times[:from]
446
+ typical.remove_interval(OpeningHoursConverter::Interval.new(wd, times[:from], wd, times[:to]))
447
+ else
448
+ if wd < 6
449
+ typical.remove_interval(OpeningHoursConverter::Interval.new(wd, times[:from], wd+1, times[:to]))
450
+ else
451
+ typical.remove_interval(OpeningHoursConverter::Interval.new(wd, times[:from], wd+1, 24*60))
452
+ typical.remove_interval(OpeningHoursConverter::Interval.new(0, 0, 0, times[:to]))
453
+ end
454
+ end
455
+ end
456
+
457
+ def add_interval(typical, weekdays, times)
458
+ if typical.instance_of?(OpeningHoursConverter::Day)
459
+ if weekdays[:from] != 0 || (weekdays[:to] !=0 && times[:from] <= times[:to])
460
+ weekdays = weekdays.dup
461
+ weekdays[:from] = 0
462
+ if times[:from] <= times[:to]
463
+ weekdays[:to] = 0
464
+ else
465
+ weekdays[:to] = 1
466
+ end
467
+ end
468
+ end
469
+
470
+ if weekdays[:from] <= weekdays[:to]
471
+ for wd in weekdays[:from]..weekdays[:to]
472
+ add_interval_wd(typical, times, wd)
473
+ end
474
+ else
475
+ for wd in weekdays[:from]..6
476
+ add_interval_wd(typical, times, wd)
477
+ end
478
+ for wd in 0..weekdays[:to]
479
+ add_interval_wd(typical, times, wd)
480
+ end
481
+ end
482
+ end
483
+
484
+ def add_interval_wd(typical, times, wd)
485
+ if times[:to] >= times[:from]
486
+ typical.add_interval(OpeningHoursConverter::Interval.new(wd, times[:from], wd, times[:to]))
487
+ else
488
+ if wd < 6
489
+ typical.add_interval(OpeningHoursConverter::Interval.new(wd, times[:from], wd+1, times[:to]))
490
+ else
491
+ typical.add_interval(OpeningHoursConverter::Interval.new(wd, times[:from], wd+1, 24*60))
492
+ typical.add_interval(OpeningHoursConverter::Interval.new(0, 0, 0, times[:to]))
493
+ end
494
+ end
495
+ end
496
+
497
+ def tokenize(block)
498
+ block.split(' ')
499
+ end
500
+
501
+ def as_minutes(time)
502
+ values = time.split(':')
503
+ values[0].to_i * 60 + values[1].to_i
504
+ end
505
+
506
+ def is_rule_modifier?(token)
507
+ !(@RGX_RULE_MODIFIER =~ token).nil?
508
+ end
509
+ def is_time?(token)
510
+ !(@RGX_TIME =~ token).nil?
511
+ end
512
+ def is_weekday?(token)
513
+ !(@RGX_WEEKDAY =~ token).nil?
514
+ end
515
+ def is_year?(token)
516
+ !(@RGX_YEAR =~ token).nil?
517
+ end
518
+ end
519
+ end
@@ -0,0 +1,99 @@
1
+ module OpeningHoursConverter
2
+ class OpeningHoursRule
3
+ attr_accessor :date, :time
4
+
5
+ def initialize
6
+ @date = []
7
+ @time = []
8
+ end
9
+
10
+ def get
11
+ result = ""
12
+ if @date.length > 1 || @date[0]&.wide != ""
13
+ @date.each_with_index do |d, i|
14
+ if (i > 0)
15
+ result += ","
16
+ end
17
+ result += d.wide
18
+ end
19
+ end
20
+
21
+ if @date.length > 0
22
+ wd = @date[0].get_weekdays
23
+ if wd.length > 0
24
+ result += " #{wd}"
25
+ end
26
+ end
27
+
28
+ if @time.length > 0
29
+ result += " "
30
+ @time.each_with_index do |t, i|
31
+ if (i > 0)
32
+ result += ","
33
+ end
34
+ result += t.get
35
+ end
36
+ else
37
+ result += " off"
38
+ end
39
+ if result.strip == "00:00-24:00"
40
+ result = "24/7"
41
+ end
42
+
43
+ result.strip
44
+ end
45
+
46
+ def same_time?(o)
47
+ if o.nil? || o.time.length != @time.length
48
+ return false
49
+ else
50
+ @time.each_with_index do |t, i|
51
+ return false if !t.equals(o.time[i])
52
+ end
53
+ return true
54
+ end
55
+ end
56
+
57
+ def is_off?
58
+ @time.length == 0 || (@time.length == 1 && time[0].start.nil?)
59
+ end
60
+
61
+ def has_overwritten_weekday?
62
+ @date.length > 0 && @date[0].weekdays_over.length > 0
63
+ end
64
+
65
+ def add_weekday(weekday)
66
+ @date.each do |d|
67
+ d.add_weekday(weekday)
68
+ end
69
+ end
70
+
71
+ def add_overwritten_weekday(weekday)
72
+ @date.each do |d|
73
+ d.add_overwritten_weekday(weekday)
74
+ end
75
+ end
76
+
77
+ def add_date(date)
78
+ if date.nil? || !date.instance_of?(OpeningHoursConverter::OpeningHoursDate)
79
+ raise ArgumentError
80
+ end
81
+
82
+ if @date.length == 0 || @date.first.wide_type != "always" && @date.first.same_kind_as?(date)
83
+ @date << date
84
+ else
85
+ if @date.length != 1 || @date.first.wide_type != "always" || !@date.first.same_weekdays?(date.weekdays)
86
+ raise ArgumentError, "This date #{@date.inspect} can't be added to this rule #{self.inspect}"
87
+ end
88
+ end
89
+ end
90
+
91
+ def add_time(time)
92
+ if (@time.length == 0 || @time[0].get != "off") && !@time.include?(time)
93
+ @time << time
94
+ else
95
+ raise ArgumentError, "This time can't be added to this rule"
96
+ end
97
+ end
98
+ end
99
+ end
@@ -0,0 +1,28 @@
1
+ module OpeningHoursConverter
2
+ class OpeningHoursTime
3
+ attr_accessor :start, :end
4
+
5
+ def initialize(minute_start=nil, minute_end=nil)
6
+ @start = minute_start
7
+ unless minute_start == minute_end
8
+ @end = minute_end
9
+ end
10
+ end
11
+
12
+ def get
13
+ return "off" if (@start.nil? && @end.nil?)
14
+ "#{time_string(@start)}#{@end.nil? ? "" : "-#{time_string(@end)}"}"
15
+ end
16
+
17
+ def equals(t)
18
+ @start == t.start && @end == t.end
19
+ end
20
+
21
+ def time_string(minutes)
22
+ fminutes = minutes.to_f
23
+ h = (fminutes/60).floor.to_i
24
+ m = (fminutes%60).to_i
25
+ "#{h < 10 ? "0" : ""}#{h}:#{m < 10 ? "0" : ""}#{m}"
26
+ end
27
+ end
28
+ end