Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
121 / 121
100.00% covered (success)
100.00%
12 / 12
CRAP
100.00% covered (success)
100.00%
1 / 1
DateTime
100.00% covered (success)
100.00%
121 / 121
100.00% covered (success)
100.00%
12 / 12
39
100.00% covered (success)
100.00%
1 / 1
 create
100.00% covered (success)
100.00%
6 / 6
100.00% covered (success)
100.00%
1 / 1
3
 setDefaultDateFormat
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 getDefaultDateFormat
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 hasDefaultDateFormat
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 setDefaultTimeFormat
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 getDefaultTimeFormat
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 hasDefaultTimeFormat
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 isDst
100.00% covered (success)
100.00%
11 / 11
100.00% covered (success)
100.00%
1 / 1
7
 getTotal
100.00% covered (success)
100.00%
28 / 28
100.00% covered (success)
100.00%
1 / 1
8
 getAverage
100.00% covered (success)
100.00%
29 / 29
100.00% covered (success)
100.00%
1 / 1
8
 getWeekDates
100.00% covered (success)
100.00%
32 / 32
100.00% covered (success)
100.00%
1 / 1
4
 __toString
100.00% covered (success)
100.00%
7 / 7
100.00% covered (success)
100.00%
1 / 1
3
1<?php
2declare(strict_types=1);
3/**
4 * Pop PHP Framework (https://www.popphp.org/)
5 *
6 * @link       https://github.com/popphp/popphp-framework
7 * @author     Nick Sagona, III <dev@noladev.com>
8 * @copyright  Copyright (c) 2009-2027 NOLA Interactive, LLC.
9 * @license    https://www.popphp.org/license     New BSD License
10 */
11
12/**
13 * @namespace
14 */
15namespace Pop\Utils;
16
17use DateTimeZone;
18use DateInterval;
19
20/**
21 * Pop utils date-time helper class
22 *
23 * @category   Pop
24 * @package    Pop\Utils
25 * @author     Nick Sagona, III <dev@noladev.com>
26 * @copyright  Copyright (c) 2009-2027 NOLA Interactive, LLC.
27 * @license    https://www.popphp.org/license     New BSD License
28 * @version    3.0.0
29 */
30class DateTime extends \DateTime
31{
32
33    use DateTimeTrait;
34
35    /**
36     * Default date format
37     * @var ?string
38     */
39    protected ?string $defaultDateFormat = null;
40
41    /**
42     * Default time format
43     * @var ?string
44     */
45    protected ?string $defaultTimeFormat = null;
46
47    /**
48     * Create a new DateTime object
49     *
50     * @param  string        $dateTime
51     * @param  ?DateTimeZone $timeZone
52     * @param  ?string       $defaultDateFormat
53     * @param  ?string       $defaultTimeFormat
54     * @throws \Exception
55     * @return static
56     */
57    public static function create(
58        string $dateTime = 'now', ?DateTimeZone $timeZone = null,
59        ?string $defaultDateFormat = null, ?string $defaultTimeFormat = null): static
60    {
61        $dt = new static($dateTime, $timeZone);
62        if ($defaultDateFormat !== null) {
63            $dt->setDefaultDateFormat($defaultDateFormat);
64        }
65        if ($defaultTimeFormat !== null) {
66            $dt->setDefaultTimeFormat($defaultTimeFormat);
67        }
68
69        return $dt;
70    }
71
72    /**
73     * Method to set the default date format
74     *
75     * @param  string $defaultDateFormat
76     * @return static
77     */
78    public function setDefaultDateFormat(string $defaultDateFormat): static
79    {
80        $this->defaultDateFormat = $defaultDateFormat;
81        return $this;
82    }
83
84    /**
85     * Method to get the default date format
86     *
87     * @return string
88     */
89    public function getDefaultDateFormat(): string
90    {
91        return $this->defaultDateFormat;
92    }
93
94    /**
95     * Method to see if the object as a default date format
96     *
97     * @return bool
98     */
99    public function hasDefaultDateFormat(): bool
100    {
101        return !empty($this->defaultDateFormat);
102    }
103
104    /**
105     * Method to set the default time format
106     *
107     * @param  string $defaultTimeFormat
108     * @return static
109     */
110    public function setDefaultTimeFormat(string $defaultTimeFormat): static
111    {
112        $this->defaultTimeFormat = $defaultTimeFormat;
113        return $this;
114    }
115
116    /**
117     * Method to get the default time format
118     *
119     * @return string
120     */
121    public function getDefaultTimeFormat(): string
122    {
123        return $this->defaultTimeFormat;
124    }
125
126    /**
127     * Method to see if the object as a default time format
128     *
129     * @return bool
130     */
131    public function hasDefaultTimeFormat(): bool
132    {
133        return !empty($this->defaultTimeFormat);
134    }
135
136    /**
137     * Method to determine if time is currently DST
138     *
139     * Standard hh:mm:ss format string is '%H:%I:%S'
140     *
141     * @param  ?string $dateTime
142     * @param  ?string $dstStart
143     * @param  ?string $dstEnd
144     * @throws \InvalidArgumentException
145     * @return bool
146     */
147    public static function isDst(?string $dateTime = null, ?string $dstStart = null, ?string $dstEnd = null): bool
148    {
149        if ($dateTime === null) {
150            $dateTime = time();
151        } else if (!is_numeric($dateTime)) {
152            $dateTime = strtotime($dateTime);
153            if ($dateTime === false) {
154                throw new \InvalidArgumentException('Error: Invalid date-time parameter.');
155            }
156        }
157
158        // Default to U.S.-based DST
159        if (($dstStart === null) || ($dstEnd === null)) {
160            $year     = date('Y', $dateTime);
161            $dstStart = strtotime('Second Sunday of March ' . $year . ' 2AM');
162            $dstEnd   = strtotime('First Sunday of November ' . $year . ' 2AM');
163        }
164
165        return (($dateTime > $dstStart) && ($dateTime < $dstEnd));
166    }
167
168    /**
169     * Method to get total time from array of multiple time values in HH:MM:SS format
170     *
171     * Standard hh:mm:ss format string is '%H:%I:%S'
172     *
173     * @param  array $times
174     * @param  ?string $format
175     * @param  bool $secondsOnly
176     * @throws \Exception
177     * @return DateInterval|string
178     */
179    public static function getTotal(array $times, ?string $format = null, bool $secondsOnly = false): DateInterval|string
180    {
181        $totalHours   = 0;
182        $totalMinutes = 0;
183        $totalSeconds = 0;
184
185        foreach ($times as $time) {
186            if ($time instanceof \DateInterval) {
187                $hours   = $time->format('%h');
188                $minutes = $time->format('%i');
189                $seconds = $time->format('%s');
190            } else {
191                if (substr_count($time, ':') == 2) {
192                    [$hours, $minutes, $seconds] = explode(':', $time);
193                } else {
194                    $hours = 0;
195                    [$minutes, $seconds] = explode(':', $time);
196                }
197            }
198            $totalHours   += (int)$hours;
199            $totalMinutes += (int)$minutes;
200            $totalSeconds += (int)$seconds;
201        }
202
203        if ($secondsOnly) {
204            $totalSeconds  += (int)$totalHours * 3600;
205            $totalSeconds  += (int)$totalMinutes * 60;
206            $intervalFormat = 'PT' . $totalSeconds . 'S';
207        } else {
208            if ($totalSeconds > 60) {
209                $totalMinutes += floor($totalSeconds / 60);
210                $totalSeconds  = $totalSeconds % 60;
211            }
212            if ($totalMinutes > 60) {
213                $totalHours  += floor($totalMinutes / 60);
214                $totalMinutes = $totalMinutes % 60;
215            }
216            $intervalFormat = 'PT' . (int)$totalHours . 'H' . (int)$totalMinutes . 'M' . (int)$totalSeconds . 'S';
217        }
218
219        $dateInterval = new DateInterval($intervalFormat);
220
221        return ($format !== null) ? $dateInterval->format($format) : $dateInterval;
222    }
223
224    /**
225     * Method to get average time from array of multiple time values in HH:MM:SS format
226     *
227     * Standard hh:mm:ss format string is '%H:%I:%S'
228     *
229     * @param  array   $times
230     * @param  ?string $format
231     * @param  bool    $secondsOnly
232     * @throws \Exception
233     * @return DateInterval|string
234     */
235    public static function getAverage(array $times, ?string $format = null, bool $secondsOnly = false): DateInterval|string
236    {
237        $total       = static::getTotal($times, null, true);
238        $totalTime   = $total->s;
239        $averageTime = round(($totalTime / count($times)), 2);
240        $hh          = 0;
241        $mm          = 0;
242        $ss          = 0;
243
244        if ($averageTime >= 3600) {
245            $hh   = floor($averageTime / 3600);
246            $mins = $averageTime - ($hh * 3600);
247            $mm   = floor($mins / 60);
248            $ss   = (int)($mins - ($mm * 60)) % 60;
249        } else if ($averageTime >= 60) {
250            $mm = floor($averageTime / 60);
251            $ss = ((int)$averageTime % 60);
252        } else {
253            $ss = $averageTime;
254        }
255
256        if ($secondsOnly) {
257            $totalSeconds   = 0;
258            $totalSeconds  += (int)$hh * 3600;
259            $totalSeconds  += (int)$mm * 60;
260            $intervalFormat = 'PT' . $totalSeconds . 'S';
261        } else {
262            $intervalFormat = 'PT';
263            if ($hh != 0) {
264                $intervalFormat .= (int)$hh . 'H';
265            }
266            if ($mm != 0) {
267                $intervalFormat .= (int)$mm . 'M';
268            }
269            if ($ss != 0) {
270                $intervalFormat .= (int)$ss . 'S';
271            }
272        }
273
274        $dateInterval = new DateInterval($intervalFormat);
275
276        return ($format !== null) ? $dateInterval->format($format) : $dateInterval;
277    }
278
279    /**
280     * Method to get dates of a week
281     *
282     * @param  ?int    $week
283     * @param  ?int    $year
284     * @param  ?string $format
285     * @return array
286     */
287    public static function getWeekDates(?int $week = null, ?int $year = null, ?string $format = null): array
288    {
289        if ($week === null) {
290            $week = (int)date('W');
291        }
292        if ($year === null) {
293            $year = (int)date('Y');
294        }
295
296        $today     = new static('today');
297        $sunday    = clone $today->setISODate($year, $week, 0);
298        $monday    = clone $today->setISODate($year, $week, 1);
299        $tuesday   = clone $today->setISODate($year, $week, 2);
300        $wednesday = clone $today->setISODate($year, $week, 3);
301        $thursday  = clone $today->setISODate($year, $week, 4);
302        $friday    = clone $today->setISODate($year, $week, 5);
303        $saturday  = clone $today->setISODate($year, $week, 6);
304
305        if ($format !== null) {
306            $weekDates = [
307                0 => $sunday->format($format),
308                1 => $monday->format($format),
309                2 => $tuesday->format($format),
310                3 => $wednesday->format($format),
311                4 => $thursday->format($format),
312                5 => $friday->format($format),
313                6 => $saturday->format($format),
314            ];
315        } else {
316            $weekDates = [
317                0 => $sunday,
318                1 => $monday,
319                2 => $tuesday,
320                3 => $wednesday,
321                4 => $thursday,
322                5 => $friday,
323                6 => $saturday,
324            ];
325        }
326
327        return $weekDates;
328    }
329
330    /**
331     * __toString method
332     *
333     * @return string
334     */
335    public function __toString(): string
336    {
337        $string = '';
338
339        if (!empty($this->defaultDateFormat)) {
340            $format = $this->defaultDateFormat;
341
342            if (!empty($this->defaultTimeFormat)) {
343                $format .= ' ' . $this->defaultTimeFormat;
344            }
345
346            $string = $this->format($format);
347        }
348
349        return $string;
350    }
351
352}
353