|
1
|
|
|
<?php |
|
2
|
|
|
|
|
3
|
|
|
/** |
|
4
|
|
|
* League.Period (https://period.thephpleague.com). |
|
5
|
|
|
* |
|
6
|
|
|
* @author Ignace Nyamagana Butera <[email protected]> |
|
7
|
|
|
* @license https://github.com/thephpleague/period/blob/master/LICENSE (MIT License) |
|
8
|
|
|
* @version 4.0.0 |
|
9
|
|
|
* @link https://github.com/thephpleague/period |
|
10
|
|
|
* |
|
11
|
|
|
* For the full copyright and license information, please view the LICENSE |
|
12
|
|
|
* file that was distributed with this source code. |
|
13
|
|
|
*/ |
|
14
|
|
|
|
|
15
|
|
|
declare(strict_types=1); |
|
16
|
|
|
|
|
17
|
|
|
namespace League\Period; |
|
18
|
|
|
|
|
19
|
|
|
use DateInterval; |
|
20
|
|
|
use DatePeriod; |
|
21
|
|
|
use DateTime; |
|
22
|
|
|
use DateTimeImmutable; |
|
23
|
|
|
use DateTimeInterface; |
|
24
|
|
|
use TypeError; |
|
25
|
|
|
use const FILTER_VALIDATE_INT; |
|
26
|
|
|
use function filter_var; |
|
27
|
|
|
use function get_class; |
|
28
|
|
|
use function gettype; |
|
29
|
|
|
use function intdiv; |
|
30
|
|
|
use function is_object; |
|
31
|
|
|
use function is_string; |
|
32
|
|
|
use function sprintf; |
|
33
|
|
|
|
|
34
|
|
|
/** |
|
35
|
|
|
* Returns a DateTimeImmutable object. |
|
36
|
|
|
*/ |
|
37
|
|
|
function datepoint($datepoint): DateTimeImmutable |
|
38
|
|
|
{ |
|
39
|
|
|
if ($datepoint instanceof DateTimeImmutable) { |
|
40
|
|
|
return $datepoint; |
|
41
|
|
|
} |
|
42
|
|
|
|
|
43
|
|
|
if ($datepoint instanceof DateTime) { |
|
44
|
|
|
return DateTimeImmutable::createFromMutable($datepoint); |
|
45
|
|
|
} |
|
46
|
|
|
|
|
47
|
|
|
if (false !== ($res = filter_var($datepoint, FILTER_VALIDATE_INT))) { |
|
48
|
|
|
return new DateTimeImmutable('@'.$res); |
|
49
|
|
|
} |
|
50
|
|
|
|
|
51
|
|
|
if (is_string($datepoint)) { |
|
52
|
|
|
return new DateTimeImmutable($datepoint); |
|
53
|
|
|
} |
|
54
|
|
|
|
|
55
|
|
|
throw new TypeError(sprintf( |
|
|
|
|
|
|
56
|
|
|
'The datepoint must be expressed using an integer, a string or a DateTimeInterface object %s given', |
|
57
|
|
|
is_object($datepoint) ? get_class($datepoint) : gettype($datepoint) |
|
58
|
|
|
)); |
|
59
|
|
|
} |
|
60
|
|
|
|
|
61
|
|
|
/** |
|
62
|
|
|
* Returns a DateInval object. |
|
63
|
|
|
* |
|
64
|
|
|
* The duration can be |
|
65
|
|
|
* <ul> |
|
66
|
|
|
* <li>a DateInterval object</li> |
|
67
|
|
|
* <li>an Interval object</li> |
|
68
|
|
|
* <li>an int interpreted as the duration expressed in seconds.</li> |
|
69
|
|
|
* <li>a string in a format supported by DateInterval::createFromDateString</li> |
|
70
|
|
|
* </ul> |
|
71
|
|
|
*/ |
|
72
|
|
|
function duration($duration): DateInterval |
|
73
|
|
|
{ |
|
74
|
|
|
if ($duration instanceof Period) { |
|
75
|
|
|
return $duration->getDateInterval(); |
|
76
|
|
|
} |
|
77
|
|
|
|
|
78
|
|
|
if ($duration instanceof DateInterval) { |
|
79
|
|
|
return $duration; |
|
80
|
|
|
} |
|
81
|
|
|
|
|
82
|
|
|
if (false !== ($res = filter_var($duration, FILTER_VALIDATE_INT))) { |
|
83
|
|
|
return new DateInterval('PT'.$res.'S'); |
|
84
|
|
|
} |
|
85
|
|
|
|
|
86
|
|
|
if (is_string($duration)) { |
|
87
|
|
|
return DateInterval::createFromDateString($duration); |
|
88
|
|
|
} |
|
89
|
|
|
|
|
90
|
|
|
throw new TypeError(sprintf( |
|
|
|
|
|
|
91
|
|
|
'The duration must be expressed using an integer, a string, a DateInterval or a Period object %s given', |
|
92
|
|
|
is_object($duration) ? get_class($duration) : gettype($duration) |
|
93
|
|
|
)); |
|
94
|
|
|
} |
|
95
|
|
|
|
|
96
|
|
|
/** |
|
97
|
|
|
* Creates new instance from a starting point and an interval. |
|
98
|
|
|
*/ |
|
99
|
|
|
function interval_after($datepoint, $duration): Period |
|
100
|
|
|
{ |
|
101
|
|
|
$datepoint = datepoint($datepoint); |
|
102
|
|
|
|
|
103
|
|
|
return new Period($datepoint, $datepoint->add(duration($duration))); |
|
104
|
|
|
} |
|
105
|
|
|
|
|
106
|
|
|
/** |
|
107
|
|
|
* Creates new instance from a ending excluded datepoint and an interval. |
|
108
|
|
|
*/ |
|
109
|
|
|
function interval_before($datepoint, $duration): Period |
|
110
|
|
|
{ |
|
111
|
|
|
$datepoint = datepoint($datepoint); |
|
112
|
|
|
|
|
113
|
|
|
return new Period($datepoint->sub(duration($duration)), $datepoint); |
|
114
|
|
|
} |
|
115
|
|
|
|
|
116
|
|
|
/** |
|
117
|
|
|
* Creates new instance where the given duration is simultaneously |
|
118
|
|
|
* substracted from and added to the datepoint. |
|
119
|
|
|
*/ |
|
120
|
|
|
function interval_around($datepoint, $duration): Period |
|
121
|
|
|
{ |
|
122
|
|
|
$datepoint = datepoint($datepoint); |
|
123
|
|
|
$duration = duration($duration); |
|
124
|
|
|
|
|
125
|
|
|
return new Period($datepoint->sub($duration), $datepoint->add($duration)); |
|
126
|
|
|
} |
|
127
|
|
|
|
|
128
|
|
|
/** |
|
129
|
|
|
* Creates new instance from a DatePeriod. |
|
130
|
|
|
* |
|
131
|
|
|
* @throws Exception If the submitted DatePeriod lacks an end datepoint. |
|
132
|
|
|
* This is possible if the DatePeriod was created using |
|
133
|
|
|
* recurrences instead of a end datepoint. |
|
134
|
|
|
* https://secure.php.net/manual/en/dateperiod.getenddate.php |
|
135
|
|
|
*/ |
|
136
|
|
|
function interval_from_dateperiod(DatePeriod $datePeriod): Period |
|
137
|
|
|
{ |
|
138
|
|
|
$endDate = $datePeriod->getEndDate(); |
|
139
|
|
|
if ($endDate instanceof DateTimeInterface) { |
|
140
|
|
|
return new Period($datePeriod->getStartDate(), $endDate); |
|
141
|
|
|
} |
|
142
|
|
|
|
|
143
|
|
|
throw new Exception('The submitted DatePeriod object does not contain an end datepoint'); |
|
144
|
|
|
} |
|
145
|
|
|
|
|
146
|
|
|
/** |
|
147
|
|
|
* Creates new instance for a specific year. |
|
148
|
|
|
* |
|
149
|
|
|
* @param mixed $int_or_datepoint a year as an int or a datepoint |
|
150
|
|
|
*/ |
|
151
|
|
|
function year($int_or_datepoint): Period |
|
152
|
|
|
{ |
|
153
|
|
|
if (is_int($int_or_datepoint)) { |
|
154
|
|
|
$startDate = (new DateTimeImmutable())->setTime(0, 0)->setDate($int_or_datepoint, 1, 1); |
|
155
|
|
|
|
|
156
|
|
|
return new Period($startDate, $startDate->add(new DateInterval('P1Y'))); |
|
157
|
|
|
} |
|
158
|
|
|
|
|
159
|
|
|
$datepoint = datepoint($int_or_datepoint); |
|
160
|
|
|
$startDate = $datepoint->setTime(0, 0)->setDate((int) $datepoint->format('Y'), 1, 1); |
|
161
|
|
|
|
|
162
|
|
|
return new Period($startDate, $startDate->add(new DateInterval('P1Y'))); |
|
163
|
|
|
} |
|
164
|
|
|
|
|
165
|
|
|
/** |
|
166
|
|
|
* Creates new instance for a specific ISO year. |
|
167
|
|
|
* |
|
168
|
|
|
* @param mixed $int_or_datepoint a year as an int or a datepoint |
|
169
|
|
|
*/ |
|
170
|
|
|
function iso_year($int_or_datepoint): Period |
|
171
|
|
|
{ |
|
172
|
|
|
if (is_int($int_or_datepoint)) { |
|
173
|
|
|
$datepoint = (new DateTimeImmutable())->setTime(0, 0); |
|
174
|
|
|
|
|
175
|
|
|
return new Period( |
|
176
|
|
|
$datepoint->setISODate($int_or_datepoint, 1), |
|
177
|
|
|
$datepoint->setISODate(++$int_or_datepoint, 1) |
|
178
|
|
|
); |
|
179
|
|
|
} |
|
180
|
|
|
|
|
181
|
|
|
$datepoint = datepoint($int_or_datepoint)->setTime(0, 0); |
|
182
|
|
|
$int_or_datepoint = (int) $datepoint->format('o'); |
|
183
|
|
|
|
|
184
|
|
|
return new Period( |
|
185
|
|
|
$datepoint->setISODate($int_or_datepoint, 1), |
|
186
|
|
|
$datepoint->setISODate(++$int_or_datepoint, 1) |
|
187
|
|
|
); |
|
188
|
|
|
} |
|
189
|
|
|
|
|
190
|
|
|
/** |
|
191
|
|
|
* Creates new instance for a specific semester in a given year. |
|
192
|
|
|
* |
|
193
|
|
|
* @param mixed $int_or_datepoint a year as an int or a datepoint |
|
194
|
|
|
* @param int $index a semester index from 1 to 2 included |
|
195
|
|
|
* |
|
196
|
|
|
* @throws Exception If the semester index is out of bounds |
|
197
|
|
|
*/ |
|
198
|
|
|
function semester($int_or_datepoint, int $index = 1): Period |
|
199
|
|
|
{ |
|
200
|
|
|
if (!is_int($int_or_datepoint)) { |
|
201
|
|
|
$datepoint = datepoint($int_or_datepoint); |
|
202
|
|
|
$startDate = $datepoint->setTime(0, 0)->setDate( |
|
203
|
|
|
(int) $datepoint->format('Y'), |
|
204
|
|
|
(intdiv((int) $datepoint->format('n'), 6) * 6) + 1, |
|
205
|
|
|
1 |
|
206
|
|
|
); |
|
207
|
|
|
|
|
208
|
|
|
return new Period($startDate, $startDate->add(new DateInterval('P6M'))); |
|
209
|
|
|
} |
|
210
|
|
|
|
|
211
|
|
|
if (0 < $index && 2 >= $index) { |
|
212
|
|
|
$startDate = (new DateTimeImmutable())->setTime(0, 0) |
|
213
|
|
|
->setDate($int_or_datepoint, (($index - 1) * 6) + 1, 1); |
|
214
|
|
|
|
|
215
|
|
|
return new Period($startDate, $startDate->add(new DateInterval('P6M'))); |
|
216
|
|
|
} |
|
217
|
|
|
|
|
218
|
|
|
throw new Exception('The semester index is not contained within the valid range.'); |
|
219
|
|
|
} |
|
220
|
|
|
|
|
221
|
|
|
/** |
|
222
|
|
|
* Creates new instance for a specific quarter in a given year. |
|
223
|
|
|
* |
|
224
|
|
|
* @param mixed $int_or_datepoint a year as an int or a datepoint |
|
225
|
|
|
* @param int $index quarter index from 1 to 4 included |
|
226
|
|
|
* |
|
227
|
|
|
* @throws Exception If the quarter index is out of bounds |
|
228
|
|
|
*/ |
|
229
|
|
|
function quarter($int_or_datepoint, int $index = 1): Period |
|
230
|
|
|
{ |
|
231
|
|
|
if (!is_int($int_or_datepoint)) { |
|
232
|
|
|
$datepoint = datepoint($int_or_datepoint)->setTime(0, 0); |
|
233
|
|
|
$startDate = $datepoint->setDate( |
|
234
|
|
|
(int) $datepoint->format('Y'), |
|
235
|
|
|
(intdiv((int) $datepoint->format('n'), 3) * 3) + 1, |
|
236
|
|
|
1 |
|
237
|
|
|
); |
|
238
|
|
|
|
|
239
|
|
|
return new Period($startDate, $startDate->add(new DateInterval('P3M'))); |
|
240
|
|
|
} |
|
241
|
|
|
|
|
242
|
|
|
if (0 < $index && 4 >= $index) { |
|
243
|
|
|
$startDate = (new DateTimeImmutable())->setTime(0, 0) |
|
244
|
|
|
->setDate($int_or_datepoint, (($index - 1) * 3) + 1, 1); |
|
245
|
|
|
|
|
246
|
|
|
return new Period($startDate, $startDate->add(new DateInterval('P3M'))); |
|
247
|
|
|
} |
|
248
|
|
|
|
|
249
|
|
|
throw new Exception('The quarter index is not contained within the valid range.'); |
|
250
|
|
|
} |
|
251
|
|
|
|
|
252
|
|
|
/** |
|
253
|
|
|
* Creates new instance for a specific year and month. |
|
254
|
|
|
* |
|
255
|
|
|
* @param mixed $int_or_datepoint a year as an int or a datepoint |
|
256
|
|
|
* @param int $index month index from 1 to 12 included |
|
257
|
|
|
* |
|
258
|
|
|
* @throws Exception If the month index is out of bounds |
|
259
|
|
|
*/ |
|
260
|
|
|
function month($int_or_datepoint, int $index = 1): Period |
|
261
|
|
|
{ |
|
262
|
|
|
if (!is_int($int_or_datepoint)) { |
|
263
|
|
|
$datepoint = datepoint($int_or_datepoint)->setTime(0, 0); |
|
264
|
|
|
$startDate = $datepoint->setDate((int) $datepoint->format('Y'), (int) $datepoint->format('n'), 1); |
|
265
|
|
|
|
|
266
|
|
|
return new Period($startDate, $startDate->add(new DateInterval('P1M'))); |
|
267
|
|
|
} |
|
268
|
|
|
|
|
269
|
|
|
if (0 < $index && 12 >= $index) { |
|
270
|
|
|
$startDate = (new DateTimeImmutable())->setTime(0, 0)->setDate($int_or_datepoint, $index, 1); |
|
271
|
|
|
|
|
272
|
|
|
return new Period($startDate, $startDate->add(new DateInterval('P1M'))); |
|
273
|
|
|
} |
|
274
|
|
|
|
|
275
|
|
|
throw new Exception('The month index is not contained within the valid range.'); |
|
276
|
|
|
} |
|
277
|
|
|
|
|
278
|
|
|
/** |
|
279
|
|
|
* Creates new instance for a specific ISO8601 week. |
|
280
|
|
|
* |
|
281
|
|
|
* @param mixed $int_or_datepoint a year as an int or a datepoint |
|
282
|
|
|
* @param int $index index from 1 to 53 included |
|
283
|
|
|
* |
|
284
|
|
|
* @throws Exception If the week index for a given year is out of bounds |
|
285
|
|
|
*/ |
|
286
|
|
|
function iso_week($int_or_datepoint, int $index = 1): Period |
|
287
|
|
|
{ |
|
288
|
|
|
if (!is_int($int_or_datepoint)) { |
|
289
|
|
|
$datepoint = datepoint($int_or_datepoint)->setTime(0, 0); |
|
290
|
|
|
$startDate = $datepoint->setISODate((int) $datepoint->format('o'), (int) $datepoint->format('W'), 1); |
|
291
|
|
|
|
|
292
|
|
|
return new Period($startDate, $startDate->add(new DateInterval('P7D'))); |
|
293
|
|
|
} |
|
294
|
|
|
|
|
295
|
|
|
$datepoint = (new DateTimeImmutable())->setTime(0, 0)->setDate($int_or_datepoint, 12, 28); |
|
296
|
|
|
if (0 < $index && (int) $datepoint->format('W') >= $index) { |
|
297
|
|
|
$startDate = $datepoint->setISODate($int_or_datepoint, $index, 1); |
|
298
|
|
|
|
|
299
|
|
|
return new Period($startDate, $startDate->add(new DateInterval('P7D'))); |
|
300
|
|
|
} |
|
301
|
|
|
|
|
302
|
|
|
throw new Exception('The week index is not contained within the valid range.'); |
|
303
|
|
|
} |
|
304
|
|
|
|
|
305
|
|
|
/** |
|
306
|
|
|
* Creates new instance for a specific date. |
|
307
|
|
|
* |
|
308
|
|
|
* The date is truncated so that the time range starts at midnight |
|
309
|
|
|
* according to the date timezone and last a full day. |
|
310
|
|
|
* |
|
311
|
|
|
* @param mixed $int_or_datepoint a year as an int or a datepoint |
|
312
|
|
|
*/ |
|
313
|
|
|
function day($int_or_datepoint, int $month = 1, int $day = 1): Period |
|
314
|
|
|
{ |
|
315
|
|
|
if (!is_int($int_or_datepoint)) { |
|
316
|
|
|
$startDate = datepoint($int_or_datepoint)->setTime(0, 0); |
|
317
|
|
|
|
|
318
|
|
|
return new Period($startDate, $startDate->add(new DateInterval('P1D'))); |
|
319
|
|
|
} |
|
320
|
|
|
|
|
321
|
|
|
if (1 > $month || 12 < $month) { |
|
322
|
|
|
throw new Exception('The month index is not contained within the valid range.'); |
|
323
|
|
|
} |
|
324
|
|
|
|
|
325
|
|
|
$datepoint = (new DateTimeImmutable())->setTime(0, 0)->setDate($int_or_datepoint, $month, 1); |
|
326
|
|
|
if (0 < $day && (int) $datepoint->format('t') >= $day) { |
|
327
|
|
|
$startDate = $datepoint->setDate($int_or_datepoint, $month, $day); |
|
328
|
|
|
|
|
329
|
|
|
return new Period($startDate, $startDate->add(new DateInterval('P1D'))); |
|
330
|
|
|
} |
|
331
|
|
|
|
|
332
|
|
|
throw new Exception('The day index is not contained within the valid range.'); |
|
333
|
|
|
} |
|
334
|
|
|
|
|
335
|
|
|
/** |
|
336
|
|
|
* Creates new instance for a specific date and hour. |
|
337
|
|
|
* |
|
338
|
|
|
* The starting datepoint represents the beginning of the hour |
|
339
|
|
|
* The interval is equal to 1 hour |
|
340
|
|
|
*/ |
|
341
|
|
|
function hour($datepoint): Period |
|
342
|
|
|
{ |
|
343
|
|
|
$datepoint = datepoint($datepoint); |
|
344
|
|
|
$startDate = $datepoint->setTime((int) $datepoint->format('H'), 0); |
|
345
|
|
|
|
|
346
|
|
|
return new Period($startDate, $startDate->add(new DateInterval('PT1H'))); |
|
347
|
|
|
} |
|
348
|
|
|
|
|
349
|
|
|
/** |
|
350
|
|
|
* Creates new instance for a specific date, hour and minute. |
|
351
|
|
|
* |
|
352
|
|
|
* The starting datepoint represents the beginning of the minute |
|
353
|
|
|
* The interval is equal to 1 minute |
|
354
|
|
|
*/ |
|
355
|
|
|
function minute($datepoint): Period |
|
356
|
|
|
{ |
|
357
|
|
|
$datepoint = datepoint($datepoint); |
|
358
|
|
|
$startDate = $datepoint->setTime((int) $datepoint->format('H'), (int) $datepoint->format('i')); |
|
359
|
|
|
|
|
360
|
|
|
return new Period($startDate, $startDate->add(new DateInterval('PT1M'))); |
|
361
|
|
|
} |
|
362
|
|
|
|
|
363
|
|
|
/** |
|
364
|
|
|
* Creates new instance for a specific date, hour, minute and second. |
|
365
|
|
|
* |
|
366
|
|
|
* The starting datepoint represents the beginning of the second |
|
367
|
|
|
* The interval is equal to 1 second |
|
368
|
|
|
*/ |
|
369
|
|
|
function second($datepoint): Period |
|
370
|
|
|
{ |
|
371
|
|
|
$datepoint = datepoint($datepoint); |
|
372
|
|
|
$startDate = $datepoint->setTime( |
|
373
|
|
|
(int) $datepoint->format('H'), |
|
374
|
|
|
(int) $datepoint->format('i'), |
|
375
|
|
|
(int) $datepoint->format('s') |
|
376
|
|
|
); |
|
377
|
|
|
|
|
378
|
|
|
return new Period($startDate, $startDate->add(new DateInterval('PT1S'))); |
|
379
|
|
|
} |
|
380
|
|
|
|
|
381
|
|
|
/** |
|
382
|
|
|
* Creates new instance for a specific datepoint. |
|
383
|
|
|
*/ |
|
384
|
|
|
function instant($datepoint): Period |
|
385
|
|
|
{ |
|
386
|
|
|
$datepoint = datepoint($datepoint); |
|
387
|
|
|
|
|
388
|
|
|
return new Period($datepoint, $datepoint); |
|
389
|
|
|
} |
|
390
|
|
|
|
This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.
If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.
In this case you can add the
@ignorePhpDoc annotation to the duplicate definition and it will be ignored.