PluginProbe
FluentBoards – Project Management, Task Management, Goal Tracking, Kanban Board, and, Team Collaboration / 1.11
FluentBoards – Project Management, Task Management, Goal Tracking, Kanban Board, and, Team Collaboration v1.11
2.1.0 2.0.15 2.0.12 2.0.10 2.0.4 2.0.1 2.0.0 1.95.3 1.95.2 1.95 1.91.6 trunk 1.11 1.12 1.13 1.20 1.21 1.22 1.23 1.30 1.31 1.32 1.35 1.40 1.41 All 42 releases
fluent-boards / vendor / wpfluent / framework / src / WPFluent / Support / DateTime.php

DateTime.php in FluentBoards – Project Management, Task Management, Goal Tracking, Kanban Board, and, Team Collaboration 1.11, at vendor/wpfluent/framework/src/WPFluent/Support/DateTime.php

819 lines 20.7 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace FluentBoards\Framework\Support;
4
5 use DateTimeZone;
6 use DateInterval;
7 use DateTimeInterface;
8 use DateTime as PHPDateTime;
9 use InvalidArgumentException;
10
11 class DateTime extends PHPDateTime
12 {
13 /**
14 * $singularUnits for checking during dynamic calls
15 * @var array
16 */
17 protected static $singularUnits = [
18 'year', 'month', 'week', 'day', 'hour', 'minute', 'second',
19 ];
20
21 /**
22 * $pluralUnits for checking during dynamic calls
23 * @var array
24 */
25 protected static $pluralUnits = [
26 'years','months', 'weeks', 'days', 'hours', 'minutes', 'seconds'
27 ];
28
29 /**
30 * Construct the DateTime Object
31 *
32 * @param string $datetime
33 * @param \DateTimeZone $timezone|null
34 */
35 public function __construct($datetime = "now", $timezone = null)
36 {
37 $timezone = $timezone ?: $this->getDefaultTimezone();
38
39 parent::__construct($datetime, $timezone);
40 }
41
42 /**
43 * Create a new DateTime Object with current time
44 *
45 * @return self
46 */
47 public static function now($tz = null)
48 {
49 return static::create('now', $tz);
50 }
51
52 /**
53 * Create a new DateTime Object with today's time
54 *
55 * @return self
56 */
57 public static function today($tz = null)
58 {
59 return static::create('today', $tz)->startOfDay();
60 }
61
62 /**
63 * Create a new DateTime Object with yesterday's time
64 *
65 * @return self
66 */
67 public static function yesterday($tz = null)
68 {
69 return static::create('now', $tz)->modify('-1 day')->startOfDay();
70 }
71
72 /**
73 * Create a new DateTime Object with tomorrow's time
74 *
75 * @return self
76 */
77 public static function tomorrow($tz = null)
78 {
79 return static::create('now', $tz)->modify('+1 day')->startOfDay();
80 }
81
82 /**
83 * Get the default timezone
84 *
85 * @return \DateTimeZone
86 */
87 public function getDefaultTimezone()
88 {
89 return wp_timezone();
90 }
91
92 /**
93 * Set the timezone
94 *
95 * @return self
96 */
97 public function timezone($tz)
98 {
99 if (is_string($tz)) {
100 $tz = new DateTimeZone($tz);
101 }
102
103 return $this->setTimezone($tz);
104 }
105
106 /**
107 * Get the default date format
108 *
109 * @return string
110 */
111 public function getDateFormat()
112 {
113 return 'Y-m-d H:i:s';
114 }
115
116 /**
117 * Check if the current instance is between two dates
118 *
119 * @param string|DateTimeInterface $date1
120 * @param string|DateTimeInterface $date2,
121 * @return bool
122 */
123 public function between($date1, $date2)
124 {
125 if (!$date1 instanceof DateTimeInterface) {
126 $date1 = new DateTime($date1);
127 }
128
129 if (!$date2 instanceof DateTimeInterface) {
130 $date2 = new DateTime($date2);
131 }
132
133 return ($this >= $date1 && $this <= $date2);
134 }
135
136 /**
137 * Create a DateTime object from a string, UNIX timestamp, or other DateTimeInterface object.
138 *
139 * @param string|int|\DateTimeInterface $time
140 * @return static
141 * @throws \Exception
142 */
143 public static function create($time = null, $tz = null)
144 {
145 if (func_num_args() > 2) {
146 return static::createFromDate(...func_get_args());
147 }
148
149 $time = $time ?: static::now();
150
151 if (is_null($tz)) {
152 $timezone = (new static)->getDefaultTimezone();
153 } else {
154 $timezone = is_string($tz) ? new DateTimeZone($tz) : $tz;
155 }
156
157 if (!$timezone instanceof DateTimeZone) {
158 throw new InvalidArgumentException('Invalid timezone.');
159 }
160
161 if ($time instanceof DateTimeInterface) {
162
163 $dateTime = new static(
164 $time->format((new static)->getDateFormat()), $time->getTimezone()
165 );
166
167 // Override the timezone if the timezone is explictly provided
168 // otherwise don't set the default timezone from $timezone.
169 !is_null($tz) && $dateTime->setTimezone($timezone);
170
171 } elseif (is_numeric($time)) {
172 if ($time <= YEAR_IN_SECONDS) {
173 $time += time();
174 }
175
176 $dateTime = new static('@' . $time);
177
178 $dateTime->setTimezone($timezone);
179
180 } else {
181 $dateTime = new static((string) $time);
182
183 // Set the timezone if timezone is explicitly provided
184 // otherwise set the default timezone if there was no
185 // timezne information available with the string.
186 if ($tz || !$dateTime->hasTimezone($time)) {
187 $dateTime->setTimezone($timezone);
188 }
189 }
190
191 return $dateTime;
192 }
193
194 /**
195 * Check if the given datetime string has the timezone
196 * information attached: Z or +/-00:00 or Asia\Dhaka.
197 *
198 * @param string $datetimeString
199 * @return boolean
200 */
201 public function hasTimezone($datetimeString)
202 {
203 // Regular expression to match timezone offset or identifier
204 $pattern = '/\b(?:[A-Z][a-zA-Z_]+\/[a-zA-Z_]+|Z|\d{2}:\d{2})\b/';
205
206 return preg_match($pattern, $datetimeString) === 1;
207 }
208
209 /**
210 * {@inheritdoc}
211 */
212 #[\ReturnTypeWillChange]
213 public static function createFromFormat($format, $datetimeString, $timezone = null)
214 {
215 if (is_null($timezone)) {
216 $timezone = (new static)->getDefaultTimezone();
217 } else {
218 $timezone = is_string($timezone) ? new DateTimeZone($timezone) : $timezone;
219 }
220
221 if (!$timezone instanceof DateTimeZone) {
222 throw new InvalidArgumentException('Invalid timezone.');
223 }
224
225 $dateTime = PHPDateTime::createFromFormat($format, $datetimeString);
226
227 if ($dateTime !== false) {
228
229 if (!$dateTime instanceof static) {
230 return new static($dateTime->format(ltrim($format, '!')), $timezone);
231 }
232
233 $dateTime->setTimezone($timezone);
234
235 return $dateTime;
236 }
237
238 throw new InvalidArgumentException(
239 "Unable to create datetime from: {$datetimeString}."
240 );
241 }
242
243 /**
244 * Create DateTime object.
245 *
246 * @return static
247 * @throws InvalidArgumentException
248 */
249 public static function createFromDate(
250 $year, $month, $day, $hour = 0, $minute = 0, $second = 0.0, $tz = null
251 ) {
252
253 $s = sprintf(
254 '%04d-%02d-%02d %02d:%02d:%02.5F', $year, $month, $day, $hour, $minute, $second
255 );
256
257 if (
258 !checkdate($month, $day, $year)
259 || $hour < 0
260 || $hour > 23
261 || $minute < 0
262 || $minute > 59
263 || $second < 0
264 || $second >= 60
265 ) {
266 throw new InvalidArgumentException("Invalid date '$s'");
267 }
268
269 return new static($s, (is_string($tz) ? new DateTimeZone($tz) : $tz));
270 }
271
272 /**
273 * Given a date in UTC or GMT timezone, returns that date in the timezone of the site.
274 *
275 * Requires a date in the Y-m-d H:i:s format.
276 * Default return format of 'Y-m-d H:i:s' can be overridden using the `$format` parameter.
277 *
278 * @param string $date_string The date to be converted, in UTC or GMT timezone.
279 * @param string $format The format string for the returned date. Default 'Y-m-d H:i:s'.
280 * @see https://developer.wordpress.org/reference/functions/get_date_from_gmt/
281 *
282 * @return string Formatted version of the date, in the site's timezone.
283 */
284 public static function createFromUTC($dateString, $format = 'Y-m-d H:i:s')
285 {
286 $date = new static(get_date_from_gmt($dateString, $format));
287
288 return $date->timezone($date->getDefaultTimezone())->format($format);
289 }
290
291 /**
292 * Parse a datetime string
293 * @param string $datetimeString
294 * @param string $timezone
295 * @return self
296 * @throws InvalidArgumentException
297 */
298 public static function parse($datetimeString, $timezone = null)
299 {
300 $parsedDate = date_parse($datetimeString);
301
302 $datetimeString = date('Y-m-d H:i:s', mktime(
303 $parsedDate['hour'],
304 $parsedDate['minute'],
305 $parsedDate['second'],
306 $parsedDate['month'],
307 $parsedDate['day'],
308 $parsedDate['year']
309 ));
310
311 if ($timezone && is_scalar($timezone)) {
312 $timezone = new DateTimeZone($timezone);
313 } elseif (isset($parsedDate['tz_id'])) {
314 $timezone = new DateTimeZone($parsedDate['tz_id']);
315 }
316
317 $dateTime = new PHPDateTime($datetimeString, $timezone);
318
319 if ($dateTime instanceof DateTimeInterface) {
320 return new static($datetimeString, $timezone);
321 }
322
323 throw new InvalidArgumentException('Unable to handle datetime.');
324 }
325
326 /**
327 * Add inetrvals, for example:
328 *
329 * add(1, day)
330 * add('2 day 8 hours 22 minutes')
331 *
332 * @param \DateInterval|string
333 * @return self
334 */
335 #[\ReturnTypeWillChange]
336 public function add($interval)
337 {
338 if ($interval instanceof DateInterval) {
339 return parent::add($interval);
340 } elseif (func_num_args() === 1 && is_string($interval)) {
341 return $this->modify('+'.$interval);
342 }
343
344 return $this->addOrSub('add', func_get_args());
345 }
346
347 /**
348 * Substruct inetrvals, for example:
349 *
350 * sub(1, day)
351 * sub('2 day 8 hours 22 minutes')
352 *
353 * @param \DateInterval $interval (optional)
354 * @return self
355 */
356 #[\ReturnTypeWillChange]
357 public function sub($interval)
358 {
359 if ($interval instanceof DateInterval) {
360 return parent::add($interval);
361 } elseif (func_num_args() === 1 && is_string($interval)) {
362 return $this->modify('-'.$interval);
363 }
364
365 return $this->addOrSub('sub', func_get_args());
366 }
367
368 /**
369 * Add or sub intervals
370 * @param string $action add/sub
371 * @param array $args
372 */
373 protected function addOrSub($action, $args)
374 {
375 $value = reset($args);
376
377 $action = $action.end($args);
378
379 return $this->{$action}($value);
380 }
381
382 /**
383 * Sets start of the year in the current dateTime
384 *
385 * @return self
386 */
387 public function startOfYear()
388 {
389 return $this->modify('first day of January')->startOfDay();
390 }
391
392 /**
393 * Sets end of the year in the current dateTime
394 *
395 * @return self
396 */
397 public function endOfYear()
398 {
399 return $this->modify('last day of December')->endOfDay();
400 }
401
402 /**
403 * Sets start of the month in the current dateTime
404 *
405 * @return self
406 */
407 public function startOfMonth()
408 {
409 return $this->modify('first day of this month')->startOfDay();
410 }
411
412 /**
413 * Sets end of the month in the current dateTime
414 *
415 * @return self
416 */
417 public function endOfMonth()
418 {
419 return $this->modify('last day of this month')->endOfDay();
420 }
421
422 /**
423 * Sets start of the week in the current dateTime
424 *
425 * @return self
426 */
427 public function startOfWeek()
428 {
429 $startOfWeek = intval(get_option('start_of_week'));
430
431 $this->modify('this week');
432
433 return $this->modify('this Sunday - ' . (7 - $startOfWeek) . ' days')->startOfDay();
434 }
435
436 /**
437 * Sets end of the week in the current dateTime
438 *
439 * @return self
440 */
441 public function endOfWeek()
442 {
443 $startOfWeek = intval(get_option('start_of_week'));
444
445 return $this->modify('this Sunday + ' . ($startOfWeek - 1) . ' days')->endOfDay();
446 }
447
448 /**
449 * Sets start of the day in the current dateTime
450 *
451 * @return self
452 */
453 public function startOfDay()
454 {
455 return $this->setTime(0, 0, 0, 0);
456 }
457
458 /**
459 * Sets end of the day in the current dateTime
460 *
461 * @return self
462 */
463 public function endOfDay()
464 {
465 return $this->setTime(23, 59, 59);
466 }
467
468 /**
469 * Sets start of the hour in the current DateTime object
470 *
471 * @return self
472 */
473 public function startOfHour()
474 {
475 return $this->setTime($this->format('H'), 0, 0, 0);
476 }
477
478 /**
479 * Sets end of the hour in the current DateTime object
480 *
481 * @return self
482 */
483 public function endOfHour()
484 {
485 return $this->setTime($this->format('H'), 59, 59, 999999);
486 }
487
488 /**
489 * Sets start of the minute in the current DateTime object
490 *
491 * @return self
492 */
493 public function startOfMinute()
494 {
495 $hour = $this->format('H');
496 $minute = $this->format('i');
497 return $this->setTime($hour, $minute, 0, 0);
498 }
499
500 /**
501 * Sets end of the minute in the current DateTime object
502 *
503 * @return self
504 */
505 public function endOfMinute()
506 {
507 $hour = $this->format('H');
508 $minute = $this->format('i');
509 return $this->setTime($hour, $minute, 59, 999999);
510 }
511
512 /**
513 * Clone the current Object
514 *
515 * @return \FluentBoards\Framework\Support\DateTime
516 */
517 public function copy()
518 {
519 return clone $this;
520 }
521
522 /**
523 * Get the difference in years
524 *
525 * @param \FluentBoards\Framework\Support\DateTime $date
526 * @return int
527 */
528 public function diffInYears($date)
529 {
530 return $this->diff($date)->y;
531 }
532
533 /**
534 * Get the difference in months
535 *
536 * @param \FluentBoards\Framework\Support\DateTime $date
537 * @return int
538 */
539 public function diffInMonths($date)
540 {
541 $diff = $this->diff($date);
542
543 return $diff->y * 12 + $diff->m;
544 }
545
546 /**
547 * Get the difference in days
548 *
549 * @param \FluentBoards\Framework\Support\DateTime $date
550 * @return int
551 */
552 public function diffInDays($date)
553 {
554 $diff = $this->diff($date);
555
556 return $diff->days;
557 }
558
559 /**
560 * Get the difference in hours
561 *
562 * @param \FluentBoards\Framework\Support\DateTime $date
563 * @return int
564 */
565 public function diffInHours($date)
566 {
567 $diff = $this->diff($date);
568
569 $diffInHours = $diff->h;
570
571 return $diffInHours + $diff->days * 24;
572 }
573
574 /**
575 * Get the difference in minutes
576 *
577 * @param \FluentBoards\Framework\Support\DateTime $date
578 * @return int
579 */
580 public function diffInMinutes($date)
581 {
582 $diff = $this->diff($date);
583
584 $diffInMinutes = $diff->i;
585
586 $diffInMinutes += $diff->h * 60;
587
588 return $diffInMinutes + $diff->days * 24 * 60;
589 }
590
591 /**
592 * Get the difference in seconds
593 *
594 * @param \FluentBoards\Framework\Support\DateTime $date
595 * @return int
596 */
597 public function diffInSeconds($date)
598 {
599 $diff = $this->diff($date);
600
601 $diffInSeconds = $diff->days * 24 * 60 * 60;
602
603 $diffInSeconds += $diff->h * 60 * 60;
604
605 $diffInSeconds += $diff->i * 60;
606
607 return $diffInSeconds + $diff->s;
608 }
609
610 /**
611 * Get human friendly time difference (2 hours ago/ 2 hours from now)
612 *
613 * @param \DateTime|string|timestamp $from The datetime to compare from
614 * @param \DateTime|string|timestamp $to The datetime to compare to (default: time())
615
616 * @return string Human readable string, ie. 5 days ago/from now
617 */
618 public function diffForHumans($from = null, $to = null)
619 {
620 // Convert the $from value to unix timestamp if needed.
621 if (is_null($from)) {
622 $from = (new DateTime($this->format($this->getDateFormat())))->getTimestamp();
623 } else {
624 if (!is_numeric($from)) {
625 $from = ($from instanceof DateTime ? $from : new DateTime($from))->getTimestamp();
626 }
627 }
628
629 // Convert the $to value to unix timestamp if needed.
630 if (!is_null($to)) {
631 if (!is_numeric($to)) {
632 $to = ($to instanceof DateTime ? $to : new DateTime($to))->getTimestamp();
633 }
634 }
635
636 $dateTime = human_time_diff($from, $to);
637
638 $diff = (time() - $from);
639
640 if ($diff > 0) {
641 if ($diff < 60) {
642 $message = sprintf(__('just now'), $dateTime);
643 } else {
644 $message = sprintf(__('%s ago'), $dateTime);
645 }
646 } else {
647 $message = sprintf(__('%s from now'), $dateTime);
648 }
649
650 return $message;
651 }
652
653 /**
654 * Given a date in the timezone of the site, returns that date in UTC.
655 *
656 * Requires and returns a date in the Y-m-d H:i:s format.
657 *
658 * Return format can be overridden using the $format parameter.
659 *
660 * @param string $dateString The date to be converted, in the timezone of the site.
661 * @param string $format The format string for the returned date. Default 'Y-m-d H:i:s'.
662 * @see https://developer.wordpress.org/reference/functions/get_gmt_from_date/
663 *
664 * @return string Formatted version of the date, in UTC.
665 */
666 public function toUTC($dateString, $format = 'Y-m-d H:i:s')
667 {
668 return get_gmt_from_date($dateString, $format);
669 }
670
671 /**
672 * Return the ISO-8601 string
673 *
674 * @see https://stackoverflow.com/a/11173072/741747
675 *
676 * @return mixed
677 */
678 public function toJSON()
679 {
680 return date('c', $this->getTimestamp());
681 }
682
683 /**
684 * Returns the formatted string
685 *
686 * @return string
687 */
688 public function toString()
689 {
690 return (string) $this;
691 }
692
693 /**
694 * Return only the date part as string
695 *
696 * @return string
697 */
698 public function toDateString()
699 {
700 return (string) $this->format('Y-m-d');
701 }
702
703 /**
704 * Return only the time part as string
705 *
706 * @return string
707 */
708 public function toTimeString()
709 {
710 return (string) $this->format('H:i:s');
711 }
712
713 /**
714 * Returns the formatted string
715 *
716 * @return string
717 */
718 public function __toString()
719 {
720 return $this->format($this->getDateFormat());
721 }
722
723 /**
724 * Getter to get an unit of DateTime
725 * @param string $key
726 * @return string|null
727 */
728 public function __get($key)
729 {
730 if ($key == 'year') {
731 return $this->format('Y');
732 } elseif ($key == 'month') {
733 return $this->format('m');
734 } elseif ($key == 'day') {
735 return $this->format('d');
736 } elseif ($key == 'hour') {
737 return $this->format('H');
738 } elseif ($key == 'minute') {
739 return $this->format('i');
740 } elseif ($key == 'second') {
741 return $this->format('s');
742 }
743 }
744
745 /**
746 * Setter to set an unit of DateTime
747 * @param string $key
748 * @param string|int $value
749 * @return self
750 */
751 public function __set($key, $value)
752 {
753 if ($key == 'year') {
754 return $this->setDate($value, $this->format('m'), $this->format('d'));
755 } elseif ($key == 'month') {
756 return $this->setDate($this->format('Y'), $value, $this->format('d'));
757 } elseif ($key == 'day') {
758 return $this->setDate($this->format('Y'), $this->format('m'), $value);
759 } elseif ($key == 'hour') {
760 return $this->setTime($value, $this->format('i'), $this->format('s'));
761 } elseif ($key == 'minute') {
762 return $this->setTime($this->format('H'), $value, $this->format('s'));
763 } elseif ($key == 'second') {
764 return $this->setTime($this->format('H'), $this->format('i'), $value);
765 }
766 }
767
768 /**
769 * Handle Dynamic calls (add/sub)
770 *
771 * @param string $method
772 * @param array $params
773 * @return self
774 */
775 public function __call($method, $params)
776 {
777 // Dynamic Setter/Getter
778 if (strpos($method, 'set') === 0) {
779 $unit = strtolower(substr($method, 3));
780 if ($params && in_array($unit, static::$singularUnits)) {
781 $this->{$unit} = reset($params);
782 return $this;
783 }
784 } elseif (strpos($method, 'get') === 0) {
785 $unit = strtolower(substr($method, 3));
786 if (in_array($unit, static::$singularUnits)) {
787 return $this->{$unit};
788 }
789 }
790
791 // Dynamic adder/subtractor
792 if (strpos($method, 'add') === 0) {
793 $action = '+';
794 } elseif (strpos($method, 'sub') === 0) {
795 $action = '-';
796 }
797
798 if (isset($action) && in_array($action, ['+', '-'])) {
799
800 if (!$params) {
801 $duration = 1;
802 } else {
803 $duration = reset($params);
804 }
805
806
807 $unit = strtolower(substr($method, 3));
808
809 $units = array_merge(static::$singularUnits, static::$pluralUnits);
810
811 if (in_array($unit, $units)) {
812 return $this->modify("{$action}{$duration}{$unit}");
813 }
814 }
815
816 throw new InvalidArgumentException("Call to undefined method {$method}.");
817 }
818 }
819