opening_hours_converter 1.8.1 → 1.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml 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