Completed
Push — master ( 611fe2...a133f4 )
by Mars
01:48
created

DataProcess::cut()   A

Complexity

Conditions 6
Paths 5

Size

Total Lines 36
Code Lines 17

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 6
eloc 17
c 1
b 0
f 0
nc 5
nop 3
dl 0
loc 36
rs 9.0777
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|string $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|string $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|string $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, get data && continue
188
                $opt[] = $tp;
189
                $timeLen = $timeLen + $tlen;
190
                // next loop
191
                continue;
192
            } elseif ($timeLen < $time) {
193
                // Partially exceeded limit
194
                $tpe = self::extendTime($tp[0], $time - $timeLen);
195
                $tp[0] != $tpe && $opt[] = [$tp[0], $tpe];
196
            }
197
198
            // Exceed the limit, exit loop
199
            break;
200
        }
201
202
        return $opt;
203
    }
204
205
    /**
206
     * Increase the time period of the specified length of time after the last time period
207
     *
208
     * 1. You can specify the smallest unit (from setUnit())
209
     * 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.
210
     * 
211
     * @param array $timePeriods            
212
     * @param number $time
213
     *            Specified length of time (default uint:second)
214
     * @param number $interval
215
     *            Interval with existing time period
216
     * @param bool|string $sortOut Whether the input needs to be rearranged. Value: true, false, 'default'. If it is 'default', see getSortOut()
217
     * @return array
218
     */
219
    public static function extend(array $timePeriods, $time, $interval = 0, $sortOut = 'default')
220
    {
221
        // Subject is empty, do nothing
222
        if (empty($timePeriods)) {
223
            return [];
224
        }
225
226
        // Data sorting out
227
        LogicalProcess::dataSortOut($sortOut, $timePeriods);
228
229
        // Convert time by unit
230
        $time = self::time2Second($time);
231
        $interval = self::time2Second($interval);
232
233
        // last time period index
234
        $eIdx = sizeof($timePeriods) - 1;
235
236
        if (!$interval) {
237
            // No gap, Directly extend the end time
238
            $timePeriods[$eIdx][1] = self::extendTime($timePeriods[$eIdx][1], $time);
239
        } else {
240
            // Has gap
241
            $tps = self::extendTime($timePeriods[$eIdx][1], $interval);
242
            $tpe = self::extendTime($tps, $time);
243
            if ($tps != $tpe) {
244
                $timePeriods[] = [$tps, $tpe];
245
            }
246
        }
247
248
        return $timePeriods;
249
    }
250
251
    /**
252
     * Shorten the specified length of time from behind
253
     *
254
     * 1. You can specify the smallest unit (from setUnit())
255
     * 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.
256
     * 
257
     * @param array $timePeriods            
258
     * @param number $time
259
     *            Specified length of time (default uint:second)
260
     * @param bool $crossperiod
261
     *            Whether to shorten across time
262
     * @param bool|string $sortOut Whether the input needs to be rearranged. Value: true, false, 'default'. If it is 'default', see getSortOut()
263
     * @return array
264
     */
265
    public static function shorten(array $timePeriods, $time, $crossperiod = true, $sortOut = 'default')
266
    {
267
        // Subject is empty, do nothing
268
        if (empty($timePeriods)) {
269
            return [];
270
        }
271
272
        // Data sorting out
273
        LogicalProcess::dataSortOut($sortOut, $timePeriods);
274
275
        // Convert time by unit
276
        $time = self::time2Second($time);
277
278
        // last time period index
279
        $eIdx = sizeof($timePeriods) - 1;
280
281
        for ($i = $eIdx; $i >= 0; $i--) {
282
            $tps = $timePeriods[$i][0];
283
            $tpe = $timePeriods[$i][1];
284
            $tTime = strtotime($tpe) - strtotime($tps);
285
286
            if ($tTime <= $time) {
287
                // Not enough, unset this timeperiod
288
                unset($timePeriods[$i]);
289
                $time -= $tTime;
290
            } else {
291
                // Enough, shorten end time.
292
                $timePeriods[$i][1] = self::extendTime($timePeriods[$i][0], $tTime - $time);
293
                break;
294
            }
295
296
            // End or No cross-period
297
            if ($time <= 0 || !$crossperiod) {
298
                break;
299
            }
300
        }
301
302
        return $timePeriods;
303
    }
304
305
    /**
306
     * Transform format
307
     * 
308
     * @param array $timePeriods
309
     * @param string $unit Time unit, if default,use class options setting
310
     * @return array
311
     */
312
    public static function format(array $timePeriods, $unit = 'default')
313
    {
314
        foreach ($timePeriods as $k => &$tp) {
315
            $tp[0] = self::timeFormatConv($tp[0], $unit);
316
            $tp[1] = self::timeFormatConv($tp[1], $unit);
317
        }
318
319
        return $timePeriods;
320
    }
321
322
    /**
323
     * Validate time period
324
     * 
325
     * Verify format, size, start/end time
326
     * 
327
     * @param mixed|array $timePeriods
328
     * @throws \Exception
329
     * @return bool
330
     */
331
    public static function validate($timePeriods)
332
    {
333
        // If not array, throw exception.
334
        (!is_array($timePeriods)) && self::throwException('Time periods format error !', 400);
335
336
        array_walk($timePeriods, function ($tp) {
337
            // filter format, number
338
            (!is_array($tp) || sizeof($tp) != 2) && self::throwException('Time periods format error !', 400);
339
340
            // filter time period
341
            $tp[0] >= $tp[1] && self::throwException('Time periods format error !', 400);
342
343
            // filter time format
344
            (self::getFilterDatetime() && (!self::isDatetime($tp[0]) || !self::isDatetime($tp[1]))) && self::throwException('Time periods format error !', 400);
345
        });
346
347
        return true;
348
    }
349
350
    /**
351
     * Remove invalid time period
352
     * 
353
     * 1. Verify format, size, start/end time, and remove invalid.
354
     * 2. time carry problem processing, e.g. 2019-01-01 24:00:00 => 2019-01-02 00:00:00
355
     * 
356
     * @param mixed|array $timePeriods
357
     * @throws \Exception
358
     * @return array
359
     */
360
    public static function filter($timePeriods)
361
    {
362
        // If not array, return.
363
        if (!is_array($timePeriods)) {
364
            return [];
365
        }
366
367
        // filter format, number
368
        $timePeriods = array_filter($timePeriods, function ($tp) {
369
            return !is_array($tp) || sizeof($tp) != 2 ? false : true;
370
        });
371
372
        // filter time period
373
        $timePeriods = array_filter($timePeriods, function ($tp) {
374
            return $tp[0] >= $tp[1] ? false : true;
375
        });
376
377
        // filter time format
378
        $timePeriods = array_filter($timePeriods, function ($tp) {
379
            return self::getFilterDatetime() && (!self::isDatetime($tp[0]) || !self::isDatetime($tp[1])) ? false : true;
380
        });
381
382
        // Time carry: ex: 2019-06-01 24:10:22 => 2019-06-02 00:10:22
383
        $timePeriods = array_map(function ($tp) {
384
            $tp[0] = substr($tp[0], 11, 2) == '24' ? self::extendTime($tp[0], 0) : $tp[0];
385
            $tp[1] = substr($tp[1], 11, 2) == '24' ? self::extendTime($tp[1], 0) : $tp[1];
386
            return $tp;
387
        }, $timePeriods);
388
389
        return $timePeriods;
390
    }
391
}
392