@@ 19-404 (lines=386) @@ | ||
16 | use GpsLab\Component\Interval\IntervalPointInterface; |
|
17 | use GpsLab\Component\Interval\IntervalType; |
|
18 | ||
19 | class DateInterval implements ComparableIntervalInterface |
|
20 | { |
|
21 | /** |
|
22 | * @var string |
|
23 | */ |
|
24 | const REGEXP = '/^ |
|
25 | (?:\(|\[) # start type char |
|
26 | \s* |
|
27 | (?<start>\d{4}-\d{2}-\d{2}) # start point |
|
28 | \s*,\s* # separator |
|
29 | (?<end>\d{4}-\d{2}-\d{2}) # end point |
|
30 | \s* |
|
31 | (?:\)|\]) # end type char |
|
32 | $/x'; |
|
33 | ||
34 | /** |
|
35 | * @var IntervalType |
|
36 | */ |
|
37 | private $type; |
|
38 | ||
39 | /** |
|
40 | * @var IntervalComparator |
|
41 | */ |
|
42 | private $comparator; |
|
43 | ||
44 | /** |
|
45 | * @var DateIntervalPoint |
|
46 | */ |
|
47 | private $start; |
|
48 | ||
49 | /** |
|
50 | * @var DateIntervalPoint |
|
51 | */ |
|
52 | private $end; |
|
53 | ||
54 | /** |
|
55 | * @param DateIntervalPoint $start |
|
56 | * @param DateIntervalPoint $end |
|
57 | * @param IntervalType $type |
|
58 | */ |
|
59 | private function __construct(DateIntervalPoint $start, DateIntervalPoint $end, IntervalType $type) |
|
60 | { |
|
61 | if ($start->gte($end)) { |
|
62 | throw IncorrectIntervalException::create(); |
|
63 | } |
|
64 | ||
65 | $this->type = $type; |
|
66 | $this->start = $start; |
|
67 | $this->end = $end; |
|
68 | $this->comparator = new IntervalComparator($this); |
|
69 | } |
|
70 | ||
71 | /** |
|
72 | * @param \DateTime $start |
|
73 | * @param \DateTime $end |
|
74 | * @param IntervalType $type |
|
75 | * |
|
76 | * @return self |
|
77 | */ |
|
78 | public static function create(\DateTime $start, \DateTime $end, IntervalType $type) |
|
79 | { |
|
80 | return new self(new DateIntervalPoint($start), new DateIntervalPoint($end), $type); |
|
81 | } |
|
82 | ||
83 | /** |
|
84 | * @param \DateTime $start |
|
85 | * @param \DateTime $end |
|
86 | * |
|
87 | * @return self |
|
88 | */ |
|
89 | public static function closed(\DateTime $start, \DateTime $end) |
|
90 | { |
|
91 | return static::create($start, $end, IntervalType::closed()); |
|
92 | } |
|
93 | ||
94 | /** |
|
95 | * @param \DateTime $start |
|
96 | * @param \DateTime $end |
|
97 | * |
|
98 | * @return self |
|
99 | */ |
|
100 | public static function halfClosed(\DateTime $start, \DateTime $end) |
|
101 | { |
|
102 | return static::create($start, $end, IntervalType::halfClosed()); |
|
103 | } |
|
104 | ||
105 | /** |
|
106 | * @param \DateTime $start |
|
107 | * @param \DateTime $end |
|
108 | * |
|
109 | * @return self |
|
110 | */ |
|
111 | public static function halfOpen(\DateTime $start, \DateTime $end) |
|
112 | { |
|
113 | return static::create($start, $end, IntervalType::halfOpen()); |
|
114 | } |
|
115 | ||
116 | /** |
|
117 | * @param \DateTime $start |
|
118 | * @param \DateTime $end |
|
119 | * |
|
120 | * @return self |
|
121 | */ |
|
122 | public static function open(\DateTime $start, \DateTime $end) |
|
123 | { |
|
124 | return static::create($start, $end, IntervalType::open()); |
|
125 | } |
|
126 | ||
127 | /** |
|
128 | * Create interval from string. |
|
129 | * |
|
130 | * Example formats for all interval types: |
|
131 | * [2016-12-09, 2016-12-21] |
|
132 | * (2015-03-07, 2015-10-19] |
|
133 | * [2014-09-11, 2015-02-08) |
|
134 | * (2013-10-27, 2013-10-30) |
|
135 | * |
|
136 | * Spaces are ignored in format. |
|
137 | * |
|
138 | * @param string $string |
|
139 | * |
|
140 | * @return self |
|
141 | */ |
|
142 | public static function fromString($string) |
|
143 | { |
|
144 | if (!preg_match(self::REGEXP, $string, $match)) { |
|
145 | throw InvalidIntervalFormatException::create('[YYYY-MM-DD, YYYY-MM-DD]', $string); |
|
146 | } |
|
147 | ||
148 | return self::create( |
|
149 | new \DateTime($match['start']), |
|
150 | new \DateTime($match['end']), |
|
151 | IntervalType::fromString($string) |
|
152 | ); |
|
153 | } |
|
154 | ||
155 | /** |
|
156 | * Checks if this interval is equal to the specified interval. |
|
157 | * |
|
158 | * @param DateInterval $interval |
|
159 | * |
|
160 | * @return bool |
|
161 | */ |
|
162 | public function equal(self $interval) |
|
163 | { |
|
164 | return $this->comparator->equal($interval); |
|
165 | } |
|
166 | ||
167 | /** |
|
168 | * Does this interval contain the specified point. |
|
169 | * |
|
170 | * @param \DateTime $point |
|
171 | * |
|
172 | * @return bool |
|
173 | */ |
|
174 | public function contains(\DateTime $point) |
|
175 | { |
|
176 | return $this->comparator->contains(new DateIntervalPoint($point)); |
|
177 | } |
|
178 | ||
179 | /** |
|
180 | * Does this interval intersect the specified interval. |
|
181 | * |
|
182 | * @param DateInterval $interval |
|
183 | * |
|
184 | * @return bool |
|
185 | */ |
|
186 | public function intersects(self $interval) |
|
187 | { |
|
188 | return $this->comparator->intersects($interval); |
|
189 | } |
|
190 | ||
191 | /** |
|
192 | * Gets the intersection between this interval and another interval. |
|
193 | * |
|
194 | * @param DateInterval $interval |
|
195 | * |
|
196 | * @return self|null |
|
197 | */ |
|
198 | public function intersection(self $interval) |
|
199 | { |
|
200 | return $this->comparator->intersection($interval); |
|
201 | } |
|
202 | ||
203 | /** |
|
204 | * Gets the covered interval between this Interval and another interval. |
|
205 | * |
|
206 | * @param DateInterval $interval |
|
207 | * |
|
208 | * @return self |
|
209 | */ |
|
210 | public function cover(self $interval) |
|
211 | { |
|
212 | return $this->comparator->cover($interval); |
|
213 | } |
|
214 | ||
215 | /** |
|
216 | * Gets the gap between this interval and another interval. |
|
217 | * |
|
218 | * @param DateInterval $interval |
|
219 | * |
|
220 | * @return self|null |
|
221 | */ |
|
222 | public function gap(self $interval) |
|
223 | { |
|
224 | return $this->comparator->gap($interval); |
|
225 | } |
|
226 | ||
227 | /** |
|
228 | * Does this interval abuts with the interval specified. |
|
229 | * |
|
230 | * @param DateInterval $interval |
|
231 | * |
|
232 | * @return bool |
|
233 | */ |
|
234 | public function abuts(self $interval) |
|
235 | { |
|
236 | return $this->comparator->abuts($interval); |
|
237 | } |
|
238 | ||
239 | /** |
|
240 | * Joins the interval between the adjacent. |
|
241 | * |
|
242 | * @param DateInterval $interval |
|
243 | * |
|
244 | * @return self|null |
|
245 | */ |
|
246 | public function join(self $interval) |
|
247 | { |
|
248 | return $this->comparator->join($interval); |
|
249 | } |
|
250 | ||
251 | /** |
|
252 | * Gets the union between this interval and another interval. |
|
253 | * |
|
254 | * @param DateInterval $interval |
|
255 | * |
|
256 | * @return self|null |
|
257 | */ |
|
258 | public function union(self $interval) |
|
259 | { |
|
260 | return $this->comparator->union($interval); |
|
261 | } |
|
262 | ||
263 | /** |
|
264 | * The point is before the interval. |
|
265 | * |
|
266 | * @param \DateTime $point |
|
267 | * |
|
268 | * @return bool |
|
269 | */ |
|
270 | public function before(\DateTime $point) |
|
271 | { |
|
272 | return $this->comparator->before(new DateIntervalPoint($point)); |
|
273 | } |
|
274 | ||
275 | /** |
|
276 | * The point is after the interval. |
|
277 | * |
|
278 | * @param \DateTime $point |
|
279 | * |
|
280 | * @return bool |
|
281 | */ |
|
282 | public function after(\DateTime $point) |
|
283 | { |
|
284 | return $this->comparator->after(new DateIntervalPoint($point)); |
|
285 | } |
|
286 | ||
287 | /** |
|
288 | * @param \DateInterval|null $step |
|
289 | * |
|
290 | * @return \Generator |
|
291 | */ |
|
292 | public function iterate(\DateInterval $step = null) |
|
293 | { |
|
294 | $step = $step ?: new \DateInterval('P1D'); |
|
295 | ||
296 | $date = $this->start(); |
|
297 | $end = $this->end(); |
|
298 | ||
299 | if ($this->type->startExcluded()) { |
|
300 | $date->add($step); |
|
301 | } |
|
302 | ||
303 | while ($date < $end || (!$this->type->endExcluded() && $date == $end)) { |
|
304 | yield $date; |
|
305 | $date->add($step); |
|
306 | } |
|
307 | } |
|
308 | ||
309 | /** |
|
310 | * @param \DateInterval|null $step |
|
311 | * |
|
312 | * @return \DatePeriod |
|
313 | */ |
|
314 | public function period(\DateInterval $step = null) |
|
315 | { |
|
316 | $step = $step ?: new \DateInterval('P1D'); |
|
317 | ||
318 | return new \DatePeriod($this->start(), $step, $this->end()); |
|
319 | } |
|
320 | ||
321 | /** |
|
322 | * @return IntervalType |
|
323 | */ |
|
324 | public function type() |
|
325 | { |
|
326 | return $this->type; |
|
327 | } |
|
328 | ||
329 | /** |
|
330 | * @return \DateTime |
|
331 | */ |
|
332 | public function start() |
|
333 | { |
|
334 | return $this->start->value(); |
|
335 | } |
|
336 | ||
337 | /** |
|
338 | * @return \DateTime |
|
339 | */ |
|
340 | public function end() |
|
341 | { |
|
342 | return $this->end->value(); |
|
343 | } |
|
344 | ||
345 | /** |
|
346 | * @return DateIntervalPoint |
|
347 | */ |
|
348 | public function startPoint() |
|
349 | { |
|
350 | return $this->start; |
|
351 | } |
|
352 | ||
353 | /** |
|
354 | * @return DateIntervalPoint |
|
355 | */ |
|
356 | public function endPoint() |
|
357 | { |
|
358 | return $this->end; |
|
359 | } |
|
360 | ||
361 | /** |
|
362 | * Returns a copy of this Interval with the start point altered. |
|
363 | * |
|
364 | * @param IntervalPointInterface|DateIntervalPoint $start |
|
365 | * |
|
366 | * @return self |
|
367 | */ |
|
368 | public function withStart(IntervalPointInterface $start) |
|
369 | { |
|
370 | return new self($start, $this->end, $this->type); |
|
371 | } |
|
372 | ||
373 | /** |
|
374 | * Returns a copy of this Interval with the end point altered. |
|
375 | * |
|
376 | * @param IntervalPointInterface|DateIntervalPoint $end |
|
377 | * |
|
378 | * @return self |
|
379 | */ |
|
380 | public function withEnd(IntervalPointInterface $end) |
|
381 | { |
|
382 | return new self($this->start, $end, $this->type); |
|
383 | } |
|
384 | ||
385 | /** |
|
386 | * Returns a copy of this Interval with the interval type altered. |
|
387 | * |
|
388 | * @param IntervalType $type |
|
389 | * |
|
390 | * @return self |
|
391 | */ |
|
392 | public function withType(IntervalType $type) |
|
393 | { |
|
394 | return new self($this->start, $this->end, $type); |
|
395 | } |
|
396 | ||
397 | /** |
|
398 | * @return string |
|
399 | */ |
|
400 | public function __toString() |
|
401 | { |
|
402 | return $this->type->formatInterval($this); |
|
403 | } |
|
404 | } |
|
405 |
@@ 19-404 (lines=386) @@ | ||
16 | use GpsLab\Component\Interval\IntervalPointInterface; |
|
17 | use GpsLab\Component\Interval\IntervalType; |
|
18 | ||
19 | class DateTimeInterval implements ComparableIntervalInterface |
|
20 | { |
|
21 | /** |
|
22 | * @var string |
|
23 | */ |
|
24 | const REGEXP = '/^ |
|
25 | (?:\(|\[) # start type char |
|
26 | \s* |
|
27 | (?<start>\d{4}-\d{2}-\d{2}\s+\d{2}:\d{2}:\d{2}) # start point |
|
28 | \s*,\s* # separator |
|
29 | (?<end>\d{4}-\d{2}-\d{2}\s+\d{2}:\d{2}:\d{2}) # end point |
|
30 | \s* |
|
31 | (?:\)|\]) # end type char |
|
32 | $/x'; |
|
33 | ||
34 | /** |
|
35 | * @var IntervalType |
|
36 | */ |
|
37 | private $type; |
|
38 | ||
39 | /** |
|
40 | * @var IntervalComparator |
|
41 | */ |
|
42 | private $comparator; |
|
43 | ||
44 | /** |
|
45 | * @var DateTimeIntervalPoint |
|
46 | */ |
|
47 | private $start; |
|
48 | ||
49 | /** |
|
50 | * @var DateTimeIntervalPoint |
|
51 | */ |
|
52 | private $end; |
|
53 | ||
54 | /** |
|
55 | * @param DateTimeIntervalPoint $start |
|
56 | * @param DateTimeIntervalPoint $end |
|
57 | * @param IntervalType $type |
|
58 | */ |
|
59 | private function __construct(DateTimeIntervalPoint $start, DateTimeIntervalPoint $end, IntervalType $type) |
|
60 | { |
|
61 | if ($start->gte($end)) { |
|
62 | throw IncorrectIntervalException::create(); |
|
63 | } |
|
64 | ||
65 | $this->type = $type; |
|
66 | $this->start = $start; |
|
67 | $this->end = $end; |
|
68 | $this->comparator = new IntervalComparator($this); |
|
69 | } |
|
70 | ||
71 | /** |
|
72 | * @param \DateTime $start |
|
73 | * @param \DateTime $end |
|
74 | * @param IntervalType $type |
|
75 | * |
|
76 | * @return self |
|
77 | */ |
|
78 | public static function create(\DateTime $start, \DateTime $end, IntervalType $type) |
|
79 | { |
|
80 | return new self(new DateTimeIntervalPoint($start), new DateTimeIntervalPoint($end), $type); |
|
81 | } |
|
82 | ||
83 | /** |
|
84 | * @param \DateTime $start |
|
85 | * @param \DateTime $end |
|
86 | * |
|
87 | * @return self |
|
88 | */ |
|
89 | public static function closed(\DateTime $start, \DateTime $end) |
|
90 | { |
|
91 | return static::create($start, $end, IntervalType::closed()); |
|
92 | } |
|
93 | ||
94 | /** |
|
95 | * @param \DateTime $start |
|
96 | * @param \DateTime $end |
|
97 | * |
|
98 | * @return self |
|
99 | */ |
|
100 | public static function halfClosed(\DateTime $start, \DateTime $end) |
|
101 | { |
|
102 | return static::create($start, $end, IntervalType::halfClosed()); |
|
103 | } |
|
104 | ||
105 | /** |
|
106 | * @param \DateTime $start |
|
107 | * @param \DateTime $end |
|
108 | * |
|
109 | * @return self |
|
110 | */ |
|
111 | public static function halfOpen(\DateTime $start, \DateTime $end) |
|
112 | { |
|
113 | return static::create($start, $end, IntervalType::halfOpen()); |
|
114 | } |
|
115 | ||
116 | /** |
|
117 | * @param \DateTime $start |
|
118 | * @param \DateTime $end |
|
119 | * |
|
120 | * @return self |
|
121 | */ |
|
122 | public static function open(\DateTime $start, \DateTime $end) |
|
123 | { |
|
124 | return static::create($start, $end, IntervalType::open()); |
|
125 | } |
|
126 | ||
127 | /** |
|
128 | * Create interval from string. |
|
129 | * |
|
130 | * Example formats for all interval types: |
|
131 | * [2016-12-09 02:55:00, 2016-12-21 12:30:12] |
|
132 | * (2015-03-07 12:04:45, 2015-10-19 19:38:14] |
|
133 | * [2014-09-11 17:31:09, 2015-02-08 23:45:58) |
|
134 | * (2013-10-27 15:03:37, 2013-10-30 05:06:34) |
|
135 | * |
|
136 | * Spaces are ignored in format. |
|
137 | * |
|
138 | * @param string $string |
|
139 | * |
|
140 | * @return self |
|
141 | */ |
|
142 | public static function fromString($string) |
|
143 | { |
|
144 | if (!preg_match(self::REGEXP, $string, $match)) { |
|
145 | throw InvalidIntervalFormatException::create('[YYYY-MM-DD HH:II:SS, YYYY-MM-DD HH:II:SS]', $string); |
|
146 | } |
|
147 | ||
148 | return self::create( |
|
149 | new \DateTime($match['start']), |
|
150 | new \DateTime($match['end']), |
|
151 | IntervalType::fromString($string) |
|
152 | ); |
|
153 | } |
|
154 | ||
155 | /** |
|
156 | * Checks if this interval is equal to the specified interval. |
|
157 | * |
|
158 | * @param DateTimeInterval $interval |
|
159 | * |
|
160 | * @return bool |
|
161 | */ |
|
162 | public function equal(self $interval) |
|
163 | { |
|
164 | return $this->comparator->equal($interval); |
|
165 | } |
|
166 | ||
167 | /** |
|
168 | * Does this interval contain the specified point. |
|
169 | * |
|
170 | * @param \DateTime $point |
|
171 | * |
|
172 | * @return bool |
|
173 | */ |
|
174 | public function contains(\DateTime $point) |
|
175 | { |
|
176 | return $this->comparator->contains(new DateTimeIntervalPoint($point)); |
|
177 | } |
|
178 | ||
179 | /** |
|
180 | * Does this interval intersect the specified interval. |
|
181 | * |
|
182 | * @param DateTimeInterval $interval |
|
183 | * |
|
184 | * @return bool |
|
185 | */ |
|
186 | public function intersects(self $interval) |
|
187 | { |
|
188 | return $this->comparator->intersects($interval); |
|
189 | } |
|
190 | ||
191 | /** |
|
192 | * Gets the intersection between this interval and another interval. |
|
193 | * |
|
194 | * @param DateTimeInterval $interval |
|
195 | * |
|
196 | * @return self|null |
|
197 | */ |
|
198 | public function intersection(self $interval) |
|
199 | { |
|
200 | return $this->comparator->intersection($interval); |
|
201 | } |
|
202 | ||
203 | /** |
|
204 | * Gets the covered interval between this Interval and another interval. |
|
205 | * |
|
206 | * @param DateTimeInterval $interval |
|
207 | * |
|
208 | * @return self |
|
209 | */ |
|
210 | public function cover(self $interval) |
|
211 | { |
|
212 | return $this->comparator->cover($interval); |
|
213 | } |
|
214 | ||
215 | /** |
|
216 | * Gets the gap between this interval and another interval. |
|
217 | * |
|
218 | * @param DateTimeInterval $interval |
|
219 | * |
|
220 | * @return self|null |
|
221 | */ |
|
222 | public function gap(self $interval) |
|
223 | { |
|
224 | return $this->comparator->gap($interval); |
|
225 | } |
|
226 | ||
227 | /** |
|
228 | * Does this interval abuts with the interval specified. |
|
229 | * |
|
230 | * @param DateTimeInterval $interval |
|
231 | * |
|
232 | * @return bool |
|
233 | */ |
|
234 | public function abuts(self $interval) |
|
235 | { |
|
236 | return $this->comparator->abuts($interval); |
|
237 | } |
|
238 | ||
239 | /** |
|
240 | * Joins the interval between the adjacent. |
|
241 | * |
|
242 | * @param DateTimeInterval $interval |
|
243 | * |
|
244 | * @return self|null |
|
245 | */ |
|
246 | public function join(self $interval) |
|
247 | { |
|
248 | return $this->comparator->join($interval); |
|
249 | } |
|
250 | ||
251 | /** |
|
252 | * Gets the union between this interval and another interval. |
|
253 | * |
|
254 | * @param DateTimeInterval $interval |
|
255 | * |
|
256 | * @return self|null |
|
257 | */ |
|
258 | public function union(self $interval) |
|
259 | { |
|
260 | return $this->comparator->union($interval); |
|
261 | } |
|
262 | ||
263 | /** |
|
264 | * The point is before the interval. |
|
265 | * |
|
266 | * @param \DateTime $point |
|
267 | * |
|
268 | * @return bool |
|
269 | */ |
|
270 | public function before(\DateTime $point) |
|
271 | { |
|
272 | return $this->comparator->before(new DateTimeIntervalPoint($point)); |
|
273 | } |
|
274 | ||
275 | /** |
|
276 | * The point is after the interval. |
|
277 | * |
|
278 | * @param \DateTime $point |
|
279 | * |
|
280 | * @return bool |
|
281 | */ |
|
282 | public function after(\DateTime $point) |
|
283 | { |
|
284 | return $this->comparator->after(new DateTimeIntervalPoint($point)); |
|
285 | } |
|
286 | ||
287 | /** |
|
288 | * @param \DateInterval|null $step |
|
289 | * |
|
290 | * @return \Generator |
|
291 | */ |
|
292 | public function iterate(\DateInterval $step = null) |
|
293 | { |
|
294 | $step = $step ?: new \DateInterval('P1D'); |
|
295 | ||
296 | $date = $this->start(); |
|
297 | $end = $this->end(); |
|
298 | ||
299 | if ($this->type->startExcluded()) { |
|
300 | $date->add($step); |
|
301 | } |
|
302 | ||
303 | while ($date < $end || (!$this->type->endExcluded() && $date == $end)) { |
|
304 | yield $date; |
|
305 | $date->add($step); |
|
306 | } |
|
307 | } |
|
308 | ||
309 | /** |
|
310 | * @param \DateInterval|null $step |
|
311 | * |
|
312 | * @return \DatePeriod |
|
313 | */ |
|
314 | public function period(\DateInterval $step = null) |
|
315 | { |
|
316 | $step = $step ?: new \DateInterval('P1D'); |
|
317 | ||
318 | return new \DatePeriod($this->start(), $step, $this->end()); |
|
319 | } |
|
320 | ||
321 | /** |
|
322 | * @return IntervalType |
|
323 | */ |
|
324 | public function type() |
|
325 | { |
|
326 | return $this->type; |
|
327 | } |
|
328 | ||
329 | /** |
|
330 | * @return \DateTime |
|
331 | */ |
|
332 | public function start() |
|
333 | { |
|
334 | return $this->start->value(); |
|
335 | } |
|
336 | ||
337 | /** |
|
338 | * @return \DateTime |
|
339 | */ |
|
340 | public function end() |
|
341 | { |
|
342 | return $this->end->value(); |
|
343 | } |
|
344 | ||
345 | /** |
|
346 | * @return DateTimeIntervalPoint |
|
347 | */ |
|
348 | public function startPoint() |
|
349 | { |
|
350 | return $this->start; |
|
351 | } |
|
352 | ||
353 | /** |
|
354 | * @return DateTimeIntervalPoint |
|
355 | */ |
|
356 | public function endPoint() |
|
357 | { |
|
358 | return $this->end; |
|
359 | } |
|
360 | ||
361 | /** |
|
362 | * Returns a copy of this Interval with the start point altered. |
|
363 | * |
|
364 | * @param IntervalPointInterface|DateTimeIntervalPoint $start |
|
365 | * |
|
366 | * @return self |
|
367 | */ |
|
368 | public function withStart(IntervalPointInterface $start) |
|
369 | { |
|
370 | return new self($start, $this->end, $this->type); |
|
371 | } |
|
372 | ||
373 | /** |
|
374 | * Returns a copy of this Interval with the end point altered. |
|
375 | * |
|
376 | * @param IntervalPointInterface|DateTimeIntervalPoint $end |
|
377 | * |
|
378 | * @return self |
|
379 | */ |
|
380 | public function withEnd(IntervalPointInterface $end) |
|
381 | { |
|
382 | return new self($this->start, $end, $this->type); |
|
383 | } |
|
384 | ||
385 | /** |
|
386 | * Returns a copy of this Interval with the interval type altered. |
|
387 | * |
|
388 | * @param IntervalType $type |
|
389 | * |
|
390 | * @return self |
|
391 | */ |
|
392 | public function withType(IntervalType $type) |
|
393 | { |
|
394 | return new self($this->start, $this->end, $type); |
|
395 | } |
|
396 | ||
397 | /** |
|
398 | * @return string |
|
399 | */ |
|
400 | public function __toString() |
|
401 | { |
|
402 | return $this->type->formatInterval($this); |
|
403 | } |
|
404 | } |
|
405 |
@@ 20-405 (lines=386) @@ | ||
17 | use GpsLab\Component\Interval\IntervalPointInterface; |
|
18 | use GpsLab\Component\Interval\IntervalType; |
|
19 | ||
20 | class MonthInterval implements ComparableIntervalInterface |
|
21 | { |
|
22 | /** |
|
23 | * @var string |
|
24 | */ |
|
25 | const REGEXP = '/^ |
|
26 | (?:\(|\[) # start type char |
|
27 | \s* |
|
28 | (?<start>\d{4}\/\d{2}) # start point |
|
29 | \s*,\s* # separator |
|
30 | (?<end>\d{4}\/\d{2}) # end point |
|
31 | \s* |
|
32 | (?:\)|\]) # end type char |
|
33 | $/x'; |
|
34 | ||
35 | /** |
|
36 | * @var IntervalType |
|
37 | */ |
|
38 | private $type; |
|
39 | ||
40 | /** |
|
41 | * @var IntervalComparator |
|
42 | */ |
|
43 | private $comparator; |
|
44 | ||
45 | /** |
|
46 | * @var MonthIntervalPoint |
|
47 | */ |
|
48 | private $start; |
|
49 | ||
50 | /** |
|
51 | * @var MonthIntervalPoint |
|
52 | */ |
|
53 | private $end; |
|
54 | ||
55 | /** |
|
56 | * @param MonthIntervalPoint $start |
|
57 | * @param MonthIntervalPoint $end |
|
58 | * @param IntervalType $type |
|
59 | */ |
|
60 | private function __construct(MonthIntervalPoint $start, MonthIntervalPoint $end, IntervalType $type) |
|
61 | { |
|
62 | if ($start->gte($end)) { |
|
63 | throw IncorrectIntervalException::create(); |
|
64 | } |
|
65 | ||
66 | $this->type = $type; |
|
67 | $this->start = $start; |
|
68 | $this->end = $end; |
|
69 | $this->comparator = new IntervalComparator($this); |
|
70 | } |
|
71 | ||
72 | /** |
|
73 | * @param \DateTime $start |
|
74 | * @param \DateTime $end |
|
75 | * @param IntervalType $type |
|
76 | * |
|
77 | * @return self |
|
78 | */ |
|
79 | public static function create(\DateTime $start, \DateTime $end, IntervalType $type) |
|
80 | { |
|
81 | return new self(new MonthIntervalPoint($start), new MonthIntervalPoint($end), $type); |
|
82 | } |
|
83 | ||
84 | /** |
|
85 | * @param \DateTime $start |
|
86 | * @param \DateTime $end |
|
87 | * |
|
88 | * @return self |
|
89 | */ |
|
90 | public static function closed(\DateTime $start, \DateTime $end) |
|
91 | { |
|
92 | return static::create($start, $end, IntervalType::closed()); |
|
93 | } |
|
94 | ||
95 | /** |
|
96 | * @param \DateTime $start |
|
97 | * @param \DateTime $end |
|
98 | * |
|
99 | * @return self |
|
100 | */ |
|
101 | public static function halfClosed(\DateTime $start, \DateTime $end) |
|
102 | { |
|
103 | return static::create($start, $end, IntervalType::halfClosed()); |
|
104 | } |
|
105 | ||
106 | /** |
|
107 | * @param \DateTime $start |
|
108 | * @param \DateTime $end |
|
109 | * |
|
110 | * @return self |
|
111 | */ |
|
112 | public static function halfOpen(\DateTime $start, \DateTime $end) |
|
113 | { |
|
114 | return static::create($start, $end, IntervalType::halfOpen()); |
|
115 | } |
|
116 | ||
117 | /** |
|
118 | * @param \DateTime $start |
|
119 | * @param \DateTime $end |
|
120 | * |
|
121 | * @return self |
|
122 | */ |
|
123 | public static function open(\DateTime $start, \DateTime $end) |
|
124 | { |
|
125 | return static::create($start, $end, IntervalType::open()); |
|
126 | } |
|
127 | ||
128 | /** |
|
129 | * Create interval from string. |
|
130 | * |
|
131 | * Example formats for all interval types: |
|
132 | * [2016/12, 2016/12] |
|
133 | * (2015/03, 2015/10] |
|
134 | * [2014/09, 2015/02) |
|
135 | * (2013/10, 2013/10) |
|
136 | * |
|
137 | * Spaces are ignored in format. |
|
138 | * |
|
139 | * @param string $string |
|
140 | * |
|
141 | * @return self |
|
142 | */ |
|
143 | public static function fromString($string) |
|
144 | { |
|
145 | if (!preg_match(self::REGEXP, $string, $match)) { |
|
146 | throw InvalidIntervalFormatException::create('[YYYY/MM, YYYY/MM]', $string); |
|
147 | } |
|
148 | ||
149 | return self::create( |
|
150 | new \DateTime($match['start'].'/01'), |
|
151 | new \DateTime($match['end'].'/01'), |
|
152 | IntervalType::fromString($string) |
|
153 | ); |
|
154 | } |
|
155 | ||
156 | /** |
|
157 | * Checks if this interval is equal to the specified interval. |
|
158 | * |
|
159 | * @param MonthInterval $interval |
|
160 | * |
|
161 | * @return bool |
|
162 | */ |
|
163 | public function equal(self $interval) |
|
164 | { |
|
165 | return $this->comparator->equal($interval); |
|
166 | } |
|
167 | ||
168 | /** |
|
169 | * Does this interval contain the specified point. |
|
170 | * |
|
171 | * @param \DateTime $point |
|
172 | * |
|
173 | * @return bool |
|
174 | */ |
|
175 | public function contains(\DateTime $point) |
|
176 | { |
|
177 | return $this->comparator->contains(new MonthIntervalPoint($point)); |
|
178 | } |
|
179 | ||
180 | /** |
|
181 | * Does this interval intersect the specified interval. |
|
182 | * |
|
183 | * @param MonthInterval $interval |
|
184 | * |
|
185 | * @return bool |
|
186 | */ |
|
187 | public function intersects(self $interval) |
|
188 | { |
|
189 | return $this->comparator->intersects($interval); |
|
190 | } |
|
191 | ||
192 | /** |
|
193 | * Gets the intersection between this interval and another interval. |
|
194 | * |
|
195 | * @param MonthInterval $interval |
|
196 | * |
|
197 | * @return self|null |
|
198 | */ |
|
199 | public function intersection(self $interval) |
|
200 | { |
|
201 | return $this->comparator->intersection($interval); |
|
202 | } |
|
203 | ||
204 | /** |
|
205 | * Gets the covered interval between this Interval and another interval. |
|
206 | * |
|
207 | * @param MonthInterval $interval |
|
208 | * |
|
209 | * @return self |
|
210 | */ |
|
211 | public function cover(self $interval) |
|
212 | { |
|
213 | return $this->comparator->cover($interval); |
|
214 | } |
|
215 | ||
216 | /** |
|
217 | * Gets the gap between this interval and another interval. |
|
218 | * |
|
219 | * @param MonthInterval $interval |
|
220 | * |
|
221 | * @return self|null |
|
222 | */ |
|
223 | public function gap(self $interval) |
|
224 | { |
|
225 | return $this->comparator->gap($interval); |
|
226 | } |
|
227 | ||
228 | /** |
|
229 | * Does this interval abuts with the interval specified. |
|
230 | * |
|
231 | * @param MonthInterval $interval |
|
232 | * |
|
233 | * @return bool |
|
234 | */ |
|
235 | public function abuts(self $interval) |
|
236 | { |
|
237 | return $this->comparator->abuts($interval); |
|
238 | } |
|
239 | ||
240 | /** |
|
241 | * Joins the interval between the adjacent. |
|
242 | * |
|
243 | * @param MonthInterval $interval |
|
244 | * |
|
245 | * @return self|null |
|
246 | */ |
|
247 | public function join(self $interval) |
|
248 | { |
|
249 | return $this->comparator->join($interval); |
|
250 | } |
|
251 | ||
252 | /** |
|
253 | * Gets the union between this interval and another interval. |
|
254 | * |
|
255 | * @param MonthInterval $interval |
|
256 | * |
|
257 | * @return self|null |
|
258 | */ |
|
259 | public function union(self $interval) |
|
260 | { |
|
261 | return $this->comparator->union($interval); |
|
262 | } |
|
263 | ||
264 | /** |
|
265 | * The point is before the interval. |
|
266 | * |
|
267 | * @param \DateTime $point |
|
268 | * |
|
269 | * @return bool |
|
270 | */ |
|
271 | public function before(\DateTime $point) |
|
272 | { |
|
273 | return $this->comparator->before(new MonthIntervalPoint($point)); |
|
274 | } |
|
275 | ||
276 | /** |
|
277 | * The point is after the interval. |
|
278 | * |
|
279 | * @param \DateTime $point |
|
280 | * |
|
281 | * @return bool |
|
282 | */ |
|
283 | public function after(\DateTime $point) |
|
284 | { |
|
285 | return $this->comparator->after(new MonthIntervalPoint($point)); |
|
286 | } |
|
287 | ||
288 | /** |
|
289 | * @param \DateInterval|null $step |
|
290 | * |
|
291 | * @return \Generator |
|
292 | */ |
|
293 | public function iterate(\DateInterval $step = null) |
|
294 | { |
|
295 | $step = $step ?: new \DateInterval('P1M'); |
|
296 | ||
297 | $date = $this->start(); |
|
298 | $end = $this->end(); |
|
299 | ||
300 | if ($this->type->startExcluded()) { |
|
301 | $date->add($step); |
|
302 | } |
|
303 | ||
304 | while ($date < $end || (!$this->type->endExcluded() && $date == $end)) { |
|
305 | yield $date; |
|
306 | $date->add($step); |
|
307 | } |
|
308 | } |
|
309 | ||
310 | /** |
|
311 | * @param \DateInterval|null $step |
|
312 | * |
|
313 | * @return \DatePeriod |
|
314 | */ |
|
315 | public function period(\DateInterval $step = null) |
|
316 | { |
|
317 | $step = $step ?: new \DateInterval('P1M'); |
|
318 | ||
319 | return new \DatePeriod($this->start(), $step, $this->end()); |
|
320 | } |
|
321 | ||
322 | /** |
|
323 | * @return IntervalType |
|
324 | */ |
|
325 | public function type() |
|
326 | { |
|
327 | return $this->type; |
|
328 | } |
|
329 | ||
330 | /** |
|
331 | * @return \DateTime |
|
332 | */ |
|
333 | public function start() |
|
334 | { |
|
335 | return $this->start->value(); |
|
336 | } |
|
337 | ||
338 | /** |
|
339 | * @return \DateTime |
|
340 | */ |
|
341 | public function end() |
|
342 | { |
|
343 | return $this->end->value(); |
|
344 | } |
|
345 | ||
346 | /** |
|
347 | * @return MonthIntervalPoint |
|
348 | */ |
|
349 | public function startPoint() |
|
350 | { |
|
351 | return $this->start; |
|
352 | } |
|
353 | ||
354 | /** |
|
355 | * @return MonthIntervalPoint |
|
356 | */ |
|
357 | public function endPoint() |
|
358 | { |
|
359 | return $this->end; |
|
360 | } |
|
361 | ||
362 | /** |
|
363 | * Returns a copy of this Interval with the start point altered. |
|
364 | * |
|
365 | * @param IntervalPointInterface|MonthIntervalPoint $start |
|
366 | * |
|
367 | * @return self |
|
368 | */ |
|
369 | public function withStart(IntervalPointInterface $start) |
|
370 | { |
|
371 | return new self($start, $this->end, $this->type); |
|
372 | } |
|
373 | ||
374 | /** |
|
375 | * Returns a copy of this Interval with the end point altered. |
|
376 | * |
|
377 | * @param IntervalPointInterface|MonthIntervalPoint $end |
|
378 | * |
|
379 | * @return self |
|
380 | */ |
|
381 | public function withEnd(IntervalPointInterface $end) |
|
382 | { |
|
383 | return new self($this->start, $end, $this->type); |
|
384 | } |
|
385 | ||
386 | /** |
|
387 | * Returns a copy of this Interval with the interval type altered. |
|
388 | * |
|
389 | * @param IntervalType $type |
|
390 | * |
|
391 | * @return self |
|
392 | */ |
|
393 | public function withType(IntervalType $type) |
|
394 | { |
|
395 | return new self($this->start, $this->end, $type); |
|
396 | } |
|
397 | ||
398 | /** |
|
399 | * @return string |
|
400 | */ |
|
401 | public function __toString() |
|
402 | { |
|
403 | return $this->type->formatInterval($this); |
|
404 | } |
|
405 | } |
|
406 |
@@ 20-405 (lines=386) @@ | ||
17 | use GpsLab\Component\Interval\IntervalPointInterface; |
|
18 | use GpsLab\Component\Interval\IntervalType; |
|
19 | ||
20 | class TimeInterval implements ComparableIntervalInterface |
|
21 | { |
|
22 | /** |
|
23 | * @var string |
|
24 | */ |
|
25 | const REGEXP = '/^ |
|
26 | (?:\(|\[) # start type char |
|
27 | \s* |
|
28 | (?<start>\d{2}:\d{2}:\d{2}) # start point |
|
29 | \s*,\s* # separator |
|
30 | (?<end>\d{2}:\d{2}:\d{2}) # end point |
|
31 | \s* |
|
32 | (?:\)|\]) # end type char |
|
33 | $/x'; |
|
34 | ||
35 | /** |
|
36 | * @var IntervalType |
|
37 | */ |
|
38 | private $type; |
|
39 | ||
40 | /** |
|
41 | * @var IntervalComparator |
|
42 | */ |
|
43 | private $comparator; |
|
44 | ||
45 | /** |
|
46 | * @var TimeIntervalPoint |
|
47 | */ |
|
48 | private $start; |
|
49 | ||
50 | /** |
|
51 | * @var TimeIntervalPoint |
|
52 | */ |
|
53 | private $end; |
|
54 | ||
55 | /** |
|
56 | * @param TimeIntervalPoint $start |
|
57 | * @param TimeIntervalPoint $end |
|
58 | * @param IntervalType $type |
|
59 | */ |
|
60 | private function __construct(TimeIntervalPoint $start, TimeIntervalPoint $end, IntervalType $type) |
|
61 | { |
|
62 | if ($start->gte($end)) { |
|
63 | throw IncorrectIntervalException::create(); |
|
64 | } |
|
65 | ||
66 | $this->type = $type; |
|
67 | $this->start = $start; |
|
68 | $this->end = $end; |
|
69 | $this->comparator = new IntervalComparator($this); |
|
70 | } |
|
71 | ||
72 | /** |
|
73 | * @param \DateTime $start |
|
74 | * @param \DateTime $end |
|
75 | * @param IntervalType $type |
|
76 | * |
|
77 | * @return self |
|
78 | */ |
|
79 | public static function create(\DateTime $start, \DateTime $end, IntervalType $type) |
|
80 | { |
|
81 | return new self(new TimeIntervalPoint($start), new TimeIntervalPoint($end), $type); |
|
82 | } |
|
83 | ||
84 | /** |
|
85 | * @param \DateTime $start |
|
86 | * @param \DateTime $end |
|
87 | * |
|
88 | * @return self |
|
89 | */ |
|
90 | public static function closed(\DateTime $start, \DateTime $end) |
|
91 | { |
|
92 | return static::create($start, $end, IntervalType::closed()); |
|
93 | } |
|
94 | ||
95 | /** |
|
96 | * @param \DateTime $start |
|
97 | * @param \DateTime $end |
|
98 | * |
|
99 | * @return self |
|
100 | */ |
|
101 | public static function halfClosed(\DateTime $start, \DateTime $end) |
|
102 | { |
|
103 | return static::create($start, $end, IntervalType::halfClosed()); |
|
104 | } |
|
105 | ||
106 | /** |
|
107 | * @param \DateTime $start |
|
108 | * @param \DateTime $end |
|
109 | * |
|
110 | * @return self |
|
111 | */ |
|
112 | public static function halfOpen(\DateTime $start, \DateTime $end) |
|
113 | { |
|
114 | return static::create($start, $end, IntervalType::halfOpen()); |
|
115 | } |
|
116 | ||
117 | /** |
|
118 | * @param \DateTime $start |
|
119 | * @param \DateTime $end |
|
120 | * |
|
121 | * @return self |
|
122 | */ |
|
123 | public static function open(\DateTime $start, \DateTime $end) |
|
124 | { |
|
125 | return static::create($start, $end, IntervalType::open()); |
|
126 | } |
|
127 | ||
128 | /** |
|
129 | * Create interval from string. |
|
130 | * |
|
131 | * Example formats for all interval types: |
|
132 | * [02:55:00, 12:30:12] |
|
133 | * (12:04:45, 19:38:14] |
|
134 | * [17:31:09, 23:45:58) |
|
135 | * (15:03:37, 15:06:34) |
|
136 | * |
|
137 | * Spaces are ignored in format. |
|
138 | * |
|
139 | * @param string $string |
|
140 | * |
|
141 | * @return self |
|
142 | */ |
|
143 | public static function fromString($string) |
|
144 | { |
|
145 | if (!preg_match(self::REGEXP, $string, $match)) { |
|
146 | throw InvalidIntervalFormatException::create('[HH:II:SS, HH:II:SS]', $string); |
|
147 | } |
|
148 | ||
149 | return self::create( |
|
150 | new \DateTime($match['start']), |
|
151 | new \DateTime($match['end']), |
|
152 | IntervalType::fromString($string) |
|
153 | ); |
|
154 | } |
|
155 | ||
156 | /** |
|
157 | * Checks if this interval is equal to the specified interval. |
|
158 | * |
|
159 | * @param TimeInterval $interval |
|
160 | * |
|
161 | * @return bool |
|
162 | */ |
|
163 | public function equal(self $interval) |
|
164 | { |
|
165 | return $this->comparator->equal($interval); |
|
166 | } |
|
167 | ||
168 | /** |
|
169 | * Does this interval contain the specified point. |
|
170 | * |
|
171 | * @param \DateTime $point |
|
172 | * |
|
173 | * @return bool |
|
174 | */ |
|
175 | public function contains(\DateTime $point) |
|
176 | { |
|
177 | return $this->comparator->contains(new TimeIntervalPoint($point)); |
|
178 | } |
|
179 | ||
180 | /** |
|
181 | * Does this interval intersect the specified interval. |
|
182 | * |
|
183 | * @param TimeInterval $interval |
|
184 | * |
|
185 | * @return bool |
|
186 | */ |
|
187 | public function intersects(self $interval) |
|
188 | { |
|
189 | return $this->comparator->intersects($interval); |
|
190 | } |
|
191 | ||
192 | /** |
|
193 | * Gets the intersection between this interval and another interval. |
|
194 | * |
|
195 | * @param TimeInterval $interval |
|
196 | * |
|
197 | * @return self|null |
|
198 | */ |
|
199 | public function intersection(self $interval) |
|
200 | { |
|
201 | return $this->comparator->intersection($interval); |
|
202 | } |
|
203 | ||
204 | /** |
|
205 | * Gets the covered interval between this Interval and another interval. |
|
206 | * |
|
207 | * @param TimeInterval $interval |
|
208 | * |
|
209 | * @return self |
|
210 | */ |
|
211 | public function cover(self $interval) |
|
212 | { |
|
213 | return $this->comparator->cover($interval); |
|
214 | } |
|
215 | ||
216 | /** |
|
217 | * Gets the gap between this interval and another interval. |
|
218 | * |
|
219 | * @param TimeInterval $interval |
|
220 | * |
|
221 | * @return self|null |
|
222 | */ |
|
223 | public function gap(self $interval) |
|
224 | { |
|
225 | return $this->comparator->gap($interval); |
|
226 | } |
|
227 | ||
228 | /** |
|
229 | * Does this interval abuts with the interval specified. |
|
230 | * |
|
231 | * @param TimeInterval $interval |
|
232 | * |
|
233 | * @return bool |
|
234 | */ |
|
235 | public function abuts(self $interval) |
|
236 | { |
|
237 | return $this->comparator->abuts($interval); |
|
238 | } |
|
239 | ||
240 | /** |
|
241 | * Joins the interval between the adjacent. |
|
242 | * |
|
243 | * @param TimeInterval $interval |
|
244 | * |
|
245 | * @return self|null |
|
246 | */ |
|
247 | public function join(self $interval) |
|
248 | { |
|
249 | return $this->comparator->join($interval); |
|
250 | } |
|
251 | ||
252 | /** |
|
253 | * Gets the union between this interval and another interval. |
|
254 | * |
|
255 | * @param TimeInterval $interval |
|
256 | * |
|
257 | * @return self|null |
|
258 | */ |
|
259 | public function union(self $interval) |
|
260 | { |
|
261 | return $this->comparator->union($interval); |
|
262 | } |
|
263 | ||
264 | /** |
|
265 | * The point is before the interval. |
|
266 | * |
|
267 | * @param \DateTime $point |
|
268 | * |
|
269 | * @return bool |
|
270 | */ |
|
271 | public function before(\DateTime $point) |
|
272 | { |
|
273 | return $this->comparator->before(new TimeIntervalPoint($point)); |
|
274 | } |
|
275 | ||
276 | /** |
|
277 | * The point is after the interval. |
|
278 | * |
|
279 | * @param \DateTime $point |
|
280 | * |
|
281 | * @return bool |
|
282 | */ |
|
283 | public function after(\DateTime $point) |
|
284 | { |
|
285 | return $this->comparator->after(new TimeIntervalPoint($point)); |
|
286 | } |
|
287 | ||
288 | /** |
|
289 | * @param \DateInterval|null $step |
|
290 | * |
|
291 | * @return \Generator |
|
292 | */ |
|
293 | public function iterate(\DateInterval $step = null) |
|
294 | { |
|
295 | $step = $step ?: new \DateInterval('PT1M'); |
|
296 | ||
297 | $date = $this->start(); |
|
298 | $end = $this->end(); |
|
299 | ||
300 | if ($this->type->startExcluded()) { |
|
301 | $date->add($step); |
|
302 | } |
|
303 | ||
304 | while ($date < $end || (!$this->type->endExcluded() && $date == $end)) { |
|
305 | yield $date; |
|
306 | $date->add($step); |
|
307 | } |
|
308 | } |
|
309 | ||
310 | /** |
|
311 | * @param \DateInterval|null $step |
|
312 | * |
|
313 | * @return \DatePeriod |
|
314 | */ |
|
315 | public function period(\DateInterval $step = null) |
|
316 | { |
|
317 | $step = $step ?: new \DateInterval('PT1M'); |
|
318 | ||
319 | return new \DatePeriod($this->start(), $step, $this->end()); |
|
320 | } |
|
321 | ||
322 | /** |
|
323 | * @return IntervalType |
|
324 | */ |
|
325 | public function type() |
|
326 | { |
|
327 | return $this->type; |
|
328 | } |
|
329 | ||
330 | /** |
|
331 | * @return \DateTime |
|
332 | */ |
|
333 | public function start() |
|
334 | { |
|
335 | return $this->start->value(); |
|
336 | } |
|
337 | ||
338 | /** |
|
339 | * @return \DateTime |
|
340 | */ |
|
341 | public function end() |
|
342 | { |
|
343 | return $this->end->value(); |
|
344 | } |
|
345 | ||
346 | /** |
|
347 | * @return TimeIntervalPoint |
|
348 | */ |
|
349 | public function startPoint() |
|
350 | { |
|
351 | return $this->start; |
|
352 | } |
|
353 | ||
354 | /** |
|
355 | * @return TimeIntervalPoint |
|
356 | */ |
|
357 | public function endPoint() |
|
358 | { |
|
359 | return $this->end; |
|
360 | } |
|
361 | ||
362 | /** |
|
363 | * Returns a copy of this Interval with the start point altered. |
|
364 | * |
|
365 | * @param IntervalPointInterface|TimeIntervalPoint $start |
|
366 | * |
|
367 | * @return self |
|
368 | */ |
|
369 | public function withStart(IntervalPointInterface $start) |
|
370 | { |
|
371 | return new self($start, $this->end, $this->type); |
|
372 | } |
|
373 | ||
374 | /** |
|
375 | * Returns a copy of this Interval with the end point altered. |
|
376 | * |
|
377 | * @param IntervalPointInterface|TimeIntervalPoint $end |
|
378 | * |
|
379 | * @return self |
|
380 | */ |
|
381 | public function withEnd(IntervalPointInterface $end) |
|
382 | { |
|
383 | return new self($this->start, $end, $this->type); |
|
384 | } |
|
385 | ||
386 | /** |
|
387 | * Returns a copy of this Interval with the interval type altered. |
|
388 | * |
|
389 | * @param IntervalType $type |
|
390 | * |
|
391 | * @return self |
|
392 | */ |
|
393 | public function withType(IntervalType $type) |
|
394 | { |
|
395 | return new self($this->start, $this->end, $type); |
|
396 | } |
|
397 | ||
398 | /** |
|
399 | * @return string |
|
400 | */ |
|
401 | public function __toString() |
|
402 | { |
|
403 | return $this->type->formatInterval($this); |
|
404 | } |
|
405 | } |
|
406 |
@@ 20-405 (lines=386) @@ | ||
17 | use GpsLab\Component\Interval\IntervalPointInterface; |
|
18 | use GpsLab\Component\Interval\IntervalType; |
|
19 | ||
20 | class WeekInterval implements ComparableIntervalInterface |
|
21 | { |
|
22 | /** |
|
23 | * @var string |
|
24 | */ |
|
25 | const REGEXP = '/^ |
|
26 | (?:\(|\[) # start type char |
|
27 | \s* |
|
28 | (?<start>\d{4}-\d{2}-\d{2}) # start point |
|
29 | \s*,\s* # separator |
|
30 | (?<end>\d{4}-\d{2}-\d{2}) # end point |
|
31 | \s* |
|
32 | (?:\)|\]) # end type char |
|
33 | $/x'; |
|
34 | ||
35 | /** |
|
36 | * @var IntervalType |
|
37 | */ |
|
38 | private $type; |
|
39 | ||
40 | /** |
|
41 | * @var IntervalComparator |
|
42 | */ |
|
43 | private $comparator; |
|
44 | ||
45 | /** |
|
46 | * @var WeekIntervalPoint |
|
47 | */ |
|
48 | private $start; |
|
49 | ||
50 | /** |
|
51 | * @var WeekIntervalPoint |
|
52 | */ |
|
53 | private $end; |
|
54 | ||
55 | /** |
|
56 | * @param WeekIntervalPoint $start |
|
57 | * @param WeekIntervalPoint $end |
|
58 | * @param IntervalType $type |
|
59 | */ |
|
60 | private function __construct(WeekIntervalPoint $start, WeekIntervalPoint $end, IntervalType $type) |
|
61 | { |
|
62 | if ($start->gte($end)) { |
|
63 | throw IncorrectIntervalException::create(); |
|
64 | } |
|
65 | ||
66 | $this->type = $type; |
|
67 | $this->start = $start; |
|
68 | $this->end = $end; |
|
69 | $this->comparator = new IntervalComparator($this); |
|
70 | } |
|
71 | ||
72 | /** |
|
73 | * @param \DateTime $start |
|
74 | * @param \DateTime $end |
|
75 | * @param IntervalType $type |
|
76 | * |
|
77 | * @return self |
|
78 | */ |
|
79 | public static function create(\DateTime $start, \DateTime $end, IntervalType $type) |
|
80 | { |
|
81 | return new self(new WeekIntervalPoint($start), new WeekIntervalPoint($end), $type); |
|
82 | } |
|
83 | ||
84 | /** |
|
85 | * @param \DateTime $start |
|
86 | * @param \DateTime $end |
|
87 | * |
|
88 | * @return self |
|
89 | */ |
|
90 | public static function closed(\DateTime $start, \DateTime $end) |
|
91 | { |
|
92 | return static::create($start, $end, IntervalType::closed()); |
|
93 | } |
|
94 | ||
95 | /** |
|
96 | * @param \DateTime $start |
|
97 | * @param \DateTime $end |
|
98 | * |
|
99 | * @return self |
|
100 | */ |
|
101 | public static function halfClosed(\DateTime $start, \DateTime $end) |
|
102 | { |
|
103 | return static::create($start, $end, IntervalType::halfClosed()); |
|
104 | } |
|
105 | ||
106 | /** |
|
107 | * @param \DateTime $start |
|
108 | * @param \DateTime $end |
|
109 | * |
|
110 | * @return self |
|
111 | */ |
|
112 | public static function halfOpen(\DateTime $start, \DateTime $end) |
|
113 | { |
|
114 | return static::create($start, $end, IntervalType::halfOpen()); |
|
115 | } |
|
116 | ||
117 | /** |
|
118 | * @param \DateTime $start |
|
119 | * @param \DateTime $end |
|
120 | * |
|
121 | * @return self |
|
122 | */ |
|
123 | public static function open(\DateTime $start, \DateTime $end) |
|
124 | { |
|
125 | return static::create($start, $end, IntervalType::open()); |
|
126 | } |
|
127 | ||
128 | /** |
|
129 | * Create interval from string. |
|
130 | * |
|
131 | * Example formats for all interval types: |
|
132 | * [2016-12-09, 2016-12-21] |
|
133 | * (2015-03-07, 2015-10-19] |
|
134 | * [2014-09-11, 2015-02-08) |
|
135 | * (2013-10-02, 2013-10-30) |
|
136 | * |
|
137 | * Spaces are ignored in format. |
|
138 | * |
|
139 | * @param string $string |
|
140 | * |
|
141 | * @return self |
|
142 | */ |
|
143 | public static function fromString($string) |
|
144 | { |
|
145 | if (!preg_match(self::REGEXP, $string, $match)) { |
|
146 | throw InvalidIntervalFormatException::create('[YYYY-MM-DD, YYYY-MM-DD]', $string); |
|
147 | } |
|
148 | ||
149 | return self::create( |
|
150 | new \DateTime($match['start']), |
|
151 | new \DateTime($match['end']), |
|
152 | IntervalType::fromString($string) |
|
153 | ); |
|
154 | } |
|
155 | ||
156 | /** |
|
157 | * Checks if this interval is equal to the specified interval. |
|
158 | * |
|
159 | * @param WeekInterval $interval |
|
160 | * |
|
161 | * @return bool |
|
162 | */ |
|
163 | public function equal(self $interval) |
|
164 | { |
|
165 | return $this->comparator->equal($interval); |
|
166 | } |
|
167 | ||
168 | /** |
|
169 | * Does this interval contain the specified point. |
|
170 | * |
|
171 | * @param \DateTime $point |
|
172 | * |
|
173 | * @return bool |
|
174 | */ |
|
175 | public function contains(\DateTime $point) |
|
176 | { |
|
177 | return $this->comparator->contains(new WeekIntervalPoint($point)); |
|
178 | } |
|
179 | ||
180 | /** |
|
181 | * Does this interval intersect the specified interval. |
|
182 | * |
|
183 | * @param WeekInterval $interval |
|
184 | * |
|
185 | * @return bool |
|
186 | */ |
|
187 | public function intersects(self $interval) |
|
188 | { |
|
189 | return $this->comparator->intersects($interval); |
|
190 | } |
|
191 | ||
192 | /** |
|
193 | * Gets the intersection between this interval and another interval. |
|
194 | * |
|
195 | * @param WeekInterval $interval |
|
196 | * |
|
197 | * @return self|null |
|
198 | */ |
|
199 | public function intersection(self $interval) |
|
200 | { |
|
201 | return $this->comparator->intersection($interval); |
|
202 | } |
|
203 | ||
204 | /** |
|
205 | * Gets the covered interval between this Interval and another interval. |
|
206 | * |
|
207 | * @param WeekInterval $interval |
|
208 | * |
|
209 | * @return self |
|
210 | */ |
|
211 | public function cover(self $interval) |
|
212 | { |
|
213 | return $this->comparator->cover($interval); |
|
214 | } |
|
215 | ||
216 | /** |
|
217 | * Gets the gap between this interval and another interval. |
|
218 | * |
|
219 | * @param WeekInterval $interval |
|
220 | * |
|
221 | * @return self|null |
|
222 | */ |
|
223 | public function gap(self $interval) |
|
224 | { |
|
225 | return $this->comparator->gap($interval); |
|
226 | } |
|
227 | ||
228 | /** |
|
229 | * Does this interval abuts with the interval specified. |
|
230 | * |
|
231 | * @param WeekInterval $interval |
|
232 | * |
|
233 | * @return bool |
|
234 | */ |
|
235 | public function abuts(self $interval) |
|
236 | { |
|
237 | return $this->comparator->abuts($interval); |
|
238 | } |
|
239 | ||
240 | /** |
|
241 | * Joins the interval between the adjacent. |
|
242 | * |
|
243 | * @param WeekInterval $interval |
|
244 | * |
|
245 | * @return self|null |
|
246 | */ |
|
247 | public function join(self $interval) |
|
248 | { |
|
249 | return $this->comparator->join($interval); |
|
250 | } |
|
251 | ||
252 | /** |
|
253 | * Gets the union between this interval and another interval. |
|
254 | * |
|
255 | * @param WeekInterval $interval |
|
256 | * |
|
257 | * @return self|null |
|
258 | */ |
|
259 | public function union(self $interval) |
|
260 | { |
|
261 | return $this->comparator->union($interval); |
|
262 | } |
|
263 | ||
264 | /** |
|
265 | * The point is before the interval. |
|
266 | * |
|
267 | * @param \DateTime $point |
|
268 | * |
|
269 | * @return bool |
|
270 | */ |
|
271 | public function before(\DateTime $point) |
|
272 | { |
|
273 | return $this->comparator->before(new WeekIntervalPoint($point)); |
|
274 | } |
|
275 | ||
276 | /** |
|
277 | * The point is after the interval. |
|
278 | * |
|
279 | * @param \DateTime $point |
|
280 | * |
|
281 | * @return bool |
|
282 | */ |
|
283 | public function after(\DateTime $point) |
|
284 | { |
|
285 | return $this->comparator->after(new WeekIntervalPoint($point)); |
|
286 | } |
|
287 | ||
288 | /** |
|
289 | * @param \DateInterval|null $step |
|
290 | * |
|
291 | * @return \Generator |
|
292 | */ |
|
293 | public function iterate(\DateInterval $step = null) |
|
294 | { |
|
295 | $step = $step ?: new \DateInterval('P1W'); |
|
296 | ||
297 | $date = $this->start(); |
|
298 | $end = $this->end(); |
|
299 | ||
300 | if ($this->type->startExcluded()) { |
|
301 | $date->add($step); |
|
302 | } |
|
303 | ||
304 | while ($date < $end || (!$this->type->endExcluded() && $date == $end)) { |
|
305 | yield $date; |
|
306 | $date->add($step); |
|
307 | } |
|
308 | } |
|
309 | ||
310 | /** |
|
311 | * @param \DateInterval|null $step |
|
312 | * |
|
313 | * @return \DatePeriod |
|
314 | */ |
|
315 | public function period(\DateInterval $step = null) |
|
316 | { |
|
317 | $step = $step ?: new \DateInterval('P1W'); |
|
318 | ||
319 | return new \DatePeriod($this->start(), $step, $this->end()); |
|
320 | } |
|
321 | ||
322 | /** |
|
323 | * @return IntervalType |
|
324 | */ |
|
325 | public function type() |
|
326 | { |
|
327 | return $this->type; |
|
328 | } |
|
329 | ||
330 | /** |
|
331 | * @return \DateTime |
|
332 | */ |
|
333 | public function start() |
|
334 | { |
|
335 | return $this->start->value(); |
|
336 | } |
|
337 | ||
338 | /** |
|
339 | * @return \DateTime |
|
340 | */ |
|
341 | public function end() |
|
342 | { |
|
343 | return $this->end->value(); |
|
344 | } |
|
345 | ||
346 | /** |
|
347 | * @return WeekIntervalPoint |
|
348 | */ |
|
349 | public function startPoint() |
|
350 | { |
|
351 | return $this->start; |
|
352 | } |
|
353 | ||
354 | /** |
|
355 | * @return WeekIntervalPoint |
|
356 | */ |
|
357 | public function endPoint() |
|
358 | { |
|
359 | return $this->end; |
|
360 | } |
|
361 | ||
362 | /** |
|
363 | * Returns a copy of this Interval with the start point altered. |
|
364 | * |
|
365 | * @param IntervalPointInterface|WeekIntervalPoint $start |
|
366 | * |
|
367 | * @return self |
|
368 | */ |
|
369 | public function withStart(IntervalPointInterface $start) |
|
370 | { |
|
371 | return new self($start, $this->end, $this->type); |
|
372 | } |
|
373 | ||
374 | /** |
|
375 | * Returns a copy of this Interval with the end point altered. |
|
376 | * |
|
377 | * @param IntervalPointInterface|WeekIntervalPoint $end |
|
378 | * |
|
379 | * @return self |
|
380 | */ |
|
381 | public function withEnd(IntervalPointInterface $end) |
|
382 | { |
|
383 | return new self($this->start, $end, $this->type); |
|
384 | } |
|
385 | ||
386 | /** |
|
387 | * Returns a copy of this Interval with the interval type altered. |
|
388 | * |
|
389 | * @param IntervalType $type |
|
390 | * |
|
391 | * @return self |
|
392 | */ |
|
393 | public function withType(IntervalType $type) |
|
394 | { |
|
395 | return new self($this->start, $this->end, $type); |
|
396 | } |
|
397 | ||
398 | /** |
|
399 | * @return string |
|
400 | */ |
|
401 | public function __toString() |
|
402 | { |
|
403 | return $this->type->formatInterval($this); |
|
404 | } |
|
405 | } |
|
406 |