Test Setup Failed
Push — master ( abb289...b06595 )
by Mars
06:56
created

DataProcess::validate()   B

Complexity

Conditions 9
Paths 6

Size

Total Lines 23
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 9
eloc 10
c 1
b 0
f 0
nc 6
nop 1
dl 0
loc 23
rs 8.0555
1
<?php
2
3
namespace marsapp\helper\timeperiod\classes;
4
5
use marsapp\helper\timeperiod\classes\Base;
6
use marsapp\helper\timeperiod\classes\LogicalProcess;
7
8
/**
9
 * Data Processing for Time Period Helper
10
 * 
11
 * @author Mars Hung <[email protected]>
12
 * @see https://github.com/marshung24/TimePeriodHelper
13
 */
14
class DataProcess extends Base
15
{
16
17
    /**
18
     * ************************************************
19
     * ************** Operation Function **************
20
     * ************************************************
21
     */
22
23
    /**
24
     * Sort time periods (Order by ASC)
25
     * 
26
     * 1. When sorting, sort the start time first, if the start time is the same, then sort the end time
27
     * 2. Sort Priority: Start Time => End Time
28
     * 
29
     * @param array $timePeriods
30
     * @return array
31
     */
32
    public static function sort(array $timePeriods)
33
    {
34
        // Closure in PHP 7.0.X loop maybe die
35
        usort($timePeriods, function ($a, $b) {
36
            if ($a[0] == $b[0]) {
37
                // Start time is equal, compare end time
38
                $r = $a[1] < $b[1] ? -1 : 1;
39
            } else {
40
                // Compare Start time
41
                $r = $a[0] < $b[0] ? -1 : 1;
42
            }
43
44
            return $r;
45
        });
46
47
        return $timePeriods;
48
    }
49
50
    /**
51
     * Fill time periods
52
     * 
53
     * Leaving only the first start time and the last end time
54
     * 
55
     * @param array $timePeriods
56
     * @return array
57
     */
58
    public static function fill(array $timePeriods)
59
    {
60
        $opt = [];
61
62
        if (isset($timePeriods[0][0])) {
63
            $tmp = array_shift($timePeriods);
64
            $start = $tmp[0];
65
            $end = $tmp[1];
66
            foreach ($timePeriods as $k => $tp) {
67
                $start = min($start, $tp[0]);
68
                $end = max($end, $tp[1]);
69
            }
70
            $opt = [[$start, $end]];
71
        }
72
73
        return $opt;
74
    }
75
76
    /**
77
     * Get gap time periods of multiple sets of time periods
78
     * 
79
     * 1. Whether $timePeriods is sorted out will affect the correctness of the results. Please refer to Note 5. Ensure performance by keeping the $timePeriods format correct.
80
     * 
81
     * @param array $timePeriods
82
     * @param bool $sortOut Whether the input needs to be rearranged. Value: true, false, 'default'. If it is 'default', see getSortOut()
83
     * @return array
84
     */
85
    public static function gap(array $timePeriods, $sortOut = 'default')
86
    {
87
        // Subject is empty, do nothing
88
        if (empty($timePeriods)) {
89
            return [];
90
        }
91
92
        // Data sorting out
93
        LogicalProcess::dataSortOut($sortOut, $timePeriods);
94
95
        $opt = [];
96
        foreach ($timePeriods as $k => $tp) {
97
            if (isset($timePeriods[$k + 1])) {
98
                $opt[] = [$tp[1], $timePeriods[$k + 1][0]];
99
            }
100
        }
101
102
        return $opt;
103
    }
104
105
    /**
106
     * Calculation period total time
107
     *
108
     * 1. You can specify the smallest unit (from setUnit())
109
     * 2. Whether $timePeriods is sorted out will affect the correctness of the results. Please refer to Note 5. Ensure performance by keeping the $timePeriods format correct.
110
     * 3. approximation: chop off
111
     *
112
     * @param array $timePeriods            
113
     * @param int $precision
114
     *            Optional decimal places for the decimal point
115
     * @param bool $sortOut Whether the input needs to be rearranged. Value: true, false, 'default'. If it is 'default', see getSortOut()
116
     * @return number
117
     */
118
    public static function time(array $timePeriods, $precision = 0, $sortOut = 'default')
119
    {
120
        // Subject is empty, do nothing
121
        if (empty($timePeriods)) {
122
            return 0;
123
        }
124
125
        // Data sorting out
126
        LogicalProcess::dataSortOut($sortOut, $timePeriods);
127
128
        // Calculate time
129
        $time = 0;
130
        foreach ($timePeriods as $k => $tp) {
131
            $time += strtotime($tp[1]) - strtotime($tp[0]);
132
        }
133
134
        // Time unit convert
135
        switch (self::getUnit('time')) {
136
            case 'minute':
137
                $time = $time / 60;
138
                break;
139
            case 'hour':
140
                $time = $time / 3600;
141
                break;
142
        }
143
144
        // Precision
145
        if ($precision > 0) {
146
            $pow = pow(10, (int) $precision);
147
            $time = ((int) ($time * $pow)) / $pow;
148
        } else {
149
            $time = (int) ($time);
150
        }
151
152
        return $time;
153
    }
154
155
    /**
156
     * Cut the time period of the specified length of time
157
     *
158
     * 1. You can specify the smallest unit (from setUnit())
159
     * 2. Whether $timePeriods is sorted out will affect the correctness of the results. Please refer to Note 5. Ensure performance by keeping the $timePeriods format correct.
160
     * 
161
     * @param array $timePeriods            
162
     * @param number $time
163
     *            Specified length of time
164
     * @param bool $sortOut Whether the input needs to be rearranged. Value: true, false, 'default'. If it is 'default', see getSortOut()
165
     * @return array
166
     */
167
    public static function cut(array $timePeriods, $time, $sortOut = 'default')
168
    {
169
        // Subject is empty, do nothing
170
        if (empty($timePeriods)) {
171
            return [];
172
        }
173
174
        // Data sorting out
175
        LogicalProcess::dataSortOut($sortOut, $timePeriods);
176
        // Convert time by unit
177
        $time = self::time2Second($time);
178
179
        $opt = [];
180
        $timeLen = 0;
181
        foreach ($timePeriods as $k => $tp) {
182
            // Calculation time
183
            $tlen = strtotime($tp[1]) - strtotime($tp[0]);
184
185
            // Judging the length of time
186
            if ($timeLen + $tlen <= $time) {
187
                // Within limits
188
                $opt[] = $tp;
189
                $timeLen = $timeLen + $tlen;
190
            } else {
191
                // Outside the limits
192
                $lastTime = $time - $timeLen;
193
                if ($lastTime > 0) {
194
                    $tps = $tp[0];
195
                    $tpe = self::extendTime($tps, $lastTime);
196
                    if ($tps != $tpe) {
197
                        $opt[] = [$tps, $tpe];
198
                    }
199
                }
200
                break;
201
            }
202
        }
203
204
        return $opt;
205
    }
206
207
    /**
208
     * Increase the time period of the specified length of time after the last time period
209
     *
210
     * 1. You can specify the smallest unit (from setUnit())
211
     * 2. Whether $timePeriods is sorted out will affect the correctness of the results. Please refer to Note 5. Ensure performance by keeping the $timePeriods format correct.
212
     * 
213
     * @param array $timePeriods            
214
     * @param number $time
215
     *            Specified length of time (default uint:second)
216
     * @param number $interval
217
     *            Interval with existing time period
218
     * @param bool $sortOut Whether the input needs to be rearranged. Value: true, false, 'default'. If it is 'default', see getSortOut()
219
     * @return array
220
     */
221
    public static function extend(array $timePeriods, $time, $interval = 0, $sortOut = 'default')
222
    {
223
        // Subject is empty, do nothing
224
        if (empty($timePeriods)) {
225
            return [];
226
        }
227
228
        // Data sorting out
229
        LogicalProcess::dataSortOut($sortOut, $timePeriods);
230
231
        // Convert time by unit
232
        $time = self::time2Second($time);
233
        $interval = self::time2Second($interval);
234
235
        // last time period index
236
        $eIdx = sizeof($timePeriods) - 1;
237
238
        if (!$interval) {
239
            // No gap, Directly extend the end time
240
            $timePeriods[$eIdx][1] = self::extendTime($timePeriods[$eIdx][1], $time);
241
        } else {
242
            // Has gap
243
            $tps = self::extendTime($timePeriods[$eIdx][1], $interval);
244
            $tpe = self::extendTime($tps, $time);
245
            if ($tps != $tpe) {
246
                $timePeriods[] = [$tps, $tpe];
247
            }
248
        }
249
250
        return $timePeriods;
251
    }
252
253
    /**
254
     * Shorten the specified length of time from behind
255
     *
256
     * 1. You can specify the smallest unit (from setUnit())
257
     * 2. Whether $timePeriods is sorted out will affect the correctness of the results. Please refer to Note 5. Ensure performance by keeping the $timePeriods format correct.
258
     * 
259
     * @param array $timePeriods            
260
     * @param number $time
261
     *            Specified length of time (default uint:second)
262
     * @param bool $crossperiod
263
     *            Whether to shorten across time
264
     * @param bool $sortOut Whether the input needs to be rearranged. Value: true, false, 'default'. If it is 'default', see getSortOut()
265
     * @return array
266
     */
267
    public static function shorten(array $timePeriods, $time, $crossperiod = true, $sortOut = 'default')
268
    {
269
        // Subject is empty, do nothing
270
        if (empty($timePeriods)) {
271
            return [];
272
        }
273
274
        // Data sorting out
275
        LogicalProcess::dataSortOut($sortOut, $timePeriods);
276
277
        // Convert time by unit
278
        $time = self::time2Second($time);
279
280
        // last time period index
281
        $eIdx = sizeof($timePeriods) - 1;
282
283
        for ($i = $eIdx; $i >= 0; $i--) {
284
            $tps = $timePeriods[$i][0];
285
            $tpe = $timePeriods[$i][1];
286
            $tTime = strtotime($tpe) - strtotime($tps);
287
288
            if ($tTime <= $time) {
289
                // Not enough, unset this timeperiod
290
                unset($timePeriods[$i]);
291
                $time -= $tTime;
292
            } else {
293
                // Enough, shorten end time.
294
                $timePeriods[$i][1] = self::extendTime($timePeriods[$i][0], $tTime - $time);
295
                break;
296
            }
297
298
            // End or No cross-period
299
            if ($time <= 0 || !$crossperiod) {
300
                break;
301
            }
302
        }
303
304
        return $timePeriods;
305
    }
306
307
    /**
308
     * Transform format
309
     * 
310
     * @param array $timePeriods
311
     * @param string $unit Time unit, if default,use class options setting
312
     * @return array
313
     */
314
    public static function format(array $timePeriods, $unit = 'default')
315
    {
316
        foreach ($timePeriods as $k => &$tp) {
317
            $tp[0] = self::timeFormatConv($tp[0], $unit);
318
            $tp[1] = self::timeFormatConv($tp[1], $unit);
319
        }
320
321
        return $timePeriods;
322
    }
323
324
    /**
325
     * Validate time period
326
     * 
327
     * Verify format, size, start/end time
328
     * 
329
     * @param mixed|array $timePeriods
330
     * @throws \Exception
331
     * @return bool
332
     */
333
    public static function validate($timePeriods)
334
    {
335
        // If not array, return.
336
        if (!is_array($timePeriods)) {
337
            throw new \Exception('Time periods format error !', 400);
338
        }
339
340
        foreach ($timePeriods as $k => $tp) {
341
            // filter format, number
342
            if (!is_array($tp) || sizeof($tp) != 2) {
343
                throw new \Exception('Time periods format error !', 400);
344
            }
345
            // filter time period
346
            if ($tp[0] >= $tp[1]) {
347
                throw new \Exception('Time periods format error !', 400);
348
            }
349
            // filter time format
350
            if (self::getFilterDatetime() && (!self::isDatetime($tp[0]) || !self::isDatetime($tp[1]))) {
351
                throw new \Exception('Time periods format error !', 400);
352
            }
353
        }
354
355
        return true;
356
    }
357
358
    /**
359
     * Remove invalid time period
360
     * 
361
     * 1. Verify format, size, start/end time, and remove invalid.
362
     * 2. time carry problem processing, e.g. 2019-01-01 24:00:00 => 2019-01-02 00:00:00
363
     * 
364
     * @param mixed|array $timePeriods
365
     * @throws \Exception
366
     * @return array
367
     */
368
    public static function filter($timePeriods)
369
    {
370
        // If not array, return.
371
        if (!is_array($timePeriods)) {
372
            return [];
373
        }
374
375
        foreach ($timePeriods as $k => $tp) {
376
            // filter format, number
377
            if (!is_array($tp) || sizeof($tp) != 2) {
378
                unset($timePeriods[$k]);
379
                continue;
380
            }
381
            // filter time period
382
            if ($tp[0] >= $tp[1]) {
383
                unset($timePeriods[$k]);
384
                continue;
385
            }
386
            // filter time format
387
            if (self::getFilterDatetime() && (!self::isDatetime($tp[0]) || !self::isDatetime($tp[1]))) {
388
                unset($timePeriods[$k]);
389
                continue;
390
            }
391
392
            // Time carry
393
            $timeLen = strlen($tp[0]);
394
            if ($timeLen >= 13) {
395
                if (substr($tp[0], 11, 2) == '24') {
396
                    $timePeriods[$k][0] = self::extendTime($timePeriods[$k][0], 0);
397
                }
398
                if (substr($tp[1], 11, 2) == '24') {
399
                    $timePeriods[$k][1] = self::extendTime($timePeriods[$k][1], 0);
400
                }
401
            }
402
        }
403
404
        return $timePeriods;
405
    }
406
}
407