Completed
Push — master ( b0ed12...5021a1 )
by ignace nyamagana
11:41
created

functions.php ➔ interval_from_dateperiod()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
nc 2
nop 1
dl 0
loc 9
rs 9.9666
c 0
b 0
f 0
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(
0 ignored issues
show
Unused Code introduced by
The call to TypeError::__construct() has too many arguments starting with \sprintf('The datepoint ...: \gettype($datepoint)).

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 @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
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(
0 ignored issues
show
Unused Code introduced by
The call to TypeError::__construct() has too many arguments starting with \sprintf('The duration m... : \gettype($duration)).

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 @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
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