PluginProbe
FluentCommunity – Ultra-Fast High-Performance Social Network, Community, LMS & Online Courses / 1.0.94
FluentCommunity – Ultra-Fast High-Performance Social Network, Community, LMS & Online Courses v1.0.94
2.10.0 2.10.01 2.9.1 2.9.0 2.8.1 2.8.0 2.7.7 2.7.5 2.7.0 2.6.01 2.6.0 2.5.0 2.4.01 trunk 1.0.90 1.0.91 1.0.92 1.0.93 1.0.94 1.0.95 1.0.96 1.0.97 1.0.98 1.0.99 1.1.0 All 77 releases
fluent-community / vendor / wpfluent / framework / src / WPFluent / Support / DateTime.php

DateTime.php in FluentCommunity – Ultra-Fast High-Performance Social Network, Community, LMS & Online Courses 1.0.94, at vendor/wpfluent/framework/src/WPFluent/Support/DateTime.php

901 lines 22.9 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace FluentCommunity\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,
138 * or other DateTimeInterface object.
139 *
140 * @param string|int|\DateTimeInterface $time
141 * @return static
142 * @throws \Exception
143 */
144 public static function create($time = null, $tz = null)
145 {
146 if (func_num_args() > 2) {
147 return static::createFromDate(...func_get_args());
148 }
149
150 $time = $time ?: static::now();
151
152 if (is_null($tz)) {
153 $timezone = (new static)->getDefaultTimezone();
154 } else {
155 $timezone = is_string($tz) ? new DateTimeZone($tz) : $tz;
156 }
157
158 if (!$timezone instanceof DateTimeZone) {
159 throw new InvalidArgumentException('Invalid timezone.');
160 }
161
162 if ($time instanceof DateTimeInterface) {
163
164 $dateTime = new static(
165 $time->format((new static)->getDateFormat()), $time->getTimezone()
166 );
167
168 // Override the timezone if the timezone is explictly provided
169 // otherwise don't set the default timezone from $timezone.
170 !is_null($tz) && $dateTime->setTimezone($timezone);
171
172 } elseif (is_numeric($time)) {
173 if ($time <= YEAR_IN_SECONDS) {
174 $time += time();
175 }
176
177 $dateTime = new static('@' . $time);
178
179 $dateTime->setTimezone($timezone);
180
181 } else {
182 $dateTime = new static((string) $time);
183
184 // Set the timezone if timezone is explicitly provided
185 // otherwise set the default timezone if there was no
186 // timezne information available with the string.
187 if ($tz || !$dateTime->hasTimezone($time)) {
188 $dateTime->setTimezone($timezone);
189 }
190 }
191
192 return $dateTime;
193 }
194
195 /**
196 * Check if the given datetime string has the timezone
197 * information attached: Z or +/-00:00 or Asia\Dhaka.
198 *
199 * @param string $datetimeString
200 * @return boolean
201 */
202 public function hasTimezone($datetimeString)
203 {
204 // Regular expression to match timezone
205 // identifier, UTC, or timezone offset
206 $pattern = '/(?:[A-Z][a-zA-Z_]+\/[a-zA-Z_]+|Z|[-+]\d{2}:\d{2})/';
207
208 return preg_match($pattern, $datetimeString) === 1;
209 }
210
211 /**
212 * {@inheritdoc}
213 */
214 #[\ReturnTypeWillChange]
215 public static function createFromFormat($format, $datetimeString, $timezone = null)
216 {
217 if (is_null($timezone)) {
218 $timezone = (new static)->getDefaultTimezone();
219 } else {
220 $timezone = is_string($timezone) ? new DateTimeZone($timezone) : $timezone;
221 }
222
223 if (!$timezone instanceof DateTimeZone) {
224 throw new InvalidArgumentException('Invalid timezone.');
225 }
226
227 $dateTime = PHPDateTime::createFromFormat($format, $datetimeString);
228
229 if ($dateTime !== false) {
230
231 if (!$dateTime instanceof static) {
232 return new static(
233 $dateTime->format(ltrim($format, '!')), $timezone
234 );
235 }
236
237 $dateTime->setTimezone($timezone);
238
239 return $dateTime;
240 }
241
242 throw new InvalidArgumentException(
243 "Unable to create datetime from: {$datetimeString}."
244 );
245 }
246
247 /**
248 * Create DateTime object.
249 *
250 * @return static
251 * @throws InvalidArgumentException
252 */
253 public static function createFromDate(
254 $year, $month, $day, $hour = 0, $minute = 0, $second = 0.0, $tz = null
255 ) {
256
257 $s = sprintf(
258 '%04d-%02d-%02d %02d:%02d:%02.5F', $year, $month, $day, $hour, $minute, $second
259 );
260
261 if (
262 !checkdate($month, $day, $year)
263 || $hour < 0
264 || $hour > 23
265 || $minute < 0
266 || $minute > 59
267 || $second < 0
268 || $second >= 60
269 ) {
270 throw new InvalidArgumentException("Invalid date '$s'");
271 }
272
273 return new static($s, (is_string($tz) ? new DateTimeZone($tz) : $tz));
274 }
275
276 /**
277 * Given a date in UTC or GMT timezone, returns
278 * that date in the timezone of the site.
279 *
280 * Requires a date in the Y-m-d H:i:s format.
281 *
282 * Default return format of 'Y-m-d H:i:s' can be
283 * overridden using the `$format` parameter.
284 *
285 * @param string $date_string The date to be converted, in UTC or GMT timezone.
286 * @param string $format The format string for the returned date. Default 'Y-m-d H:i:s'.
287 * @see https://developer.wordpress.org/reference/functions/get_date_from_gmt/
288 *
289 * @return string Formatted version of the date, in the site's timezone.
290 */
291 public static function createFromUTC($dateString, $format = 'Y-m-d H:i:s')
292 {
293 $date = new static(get_date_from_gmt($dateString, $format));
294
295 return $date->timezone($date->getDefaultTimezone())->format($format);
296 }
297
298 /**
299 * Parse a datetime string
300 * @param string $datetimeString
301 * @param string $timezone
302 * @return self
303 * @throws InvalidArgumentException
304 */
305 public static function parse($datetimeString, $timezone = null)
306 {
307 $parsedDate = date_parse($datetimeString);
308
309 $datetimeString = date('Y-m-d H:i:s', mktime(
310 $parsedDate['hour'],
311 $parsedDate['minute'],
312 $parsedDate['second'],
313 $parsedDate['month'],
314 $parsedDate['day'],
315 $parsedDate['year']
316 ));
317
318 if ($timezone && is_scalar($timezone)) {
319 $timezone = new DateTimeZone($timezone);
320 } elseif (isset($parsedDate['tz_id'])) {
321 $timezone = new DateTimeZone($parsedDate['tz_id']);
322 }
323
324 $dateTime = new PHPDateTime($datetimeString, $timezone);
325
326 if ($dateTime instanceof DateTimeInterface) {
327 return new static($datetimeString, $timezone);
328 }
329
330 throw new InvalidArgumentException('Unable to handle datetime.');
331 }
332
333 /**
334 * Add inetrvals, for example:
335 *
336 * add(1, day)
337 * add('2 day 8 hours 22 minutes')
338 *
339 * @param \DateInterval|string
340 * @return self
341 */
342 #[\ReturnTypeWillChange]
343 public function add($interval)
344 {
345 if ($interval instanceof DateInterval) {
346 return parent::add($interval);
347 } elseif (func_num_args() === 1 && is_string($interval)) {
348 return $this->modify('+'.$interval);
349 }
350
351 return $this->addOrSub('add', func_get_args());
352 }
353
354 /**
355 * Substruct inetrvals, for example:
356 *
357 * sub(1, day)
358 * sub('2 day 8 hours 22 minutes')
359 *
360 * @param \DateInterval $interval (optional)
361 * @return self
362 */
363 #[\ReturnTypeWillChange]
364 public function sub($interval)
365 {
366 if ($interval instanceof DateInterval) {
367 return parent::add($interval);
368 } elseif (func_num_args() === 1 && is_string($interval)) {
369 return $this->modify('-'.$interval);
370 }
371
372 return $this->addOrSub('sub', func_get_args());
373 }
374
375 /**
376 * Add or sub intervals
377 * @param string $action add/sub
378 * @param array $args
379 */
380 protected function addOrSub($action, $args)
381 {
382 $value = reset($args);
383
384 $action = $action.end($args);
385
386 return $this->{$action}($value);
387 }
388
389 /**
390 * Sets start of the year in the current dateTime
391 *
392 * @return self
393 */
394 public function startOfYear()
395 {
396 return $this->modify('first day of January')->startOfDay();
397 }
398
399 /**
400 * Sets end of the year in the current dateTime
401 *
402 * @return self
403 */
404 public function endOfYear()
405 {
406 return $this->modify('last day of December')->endOfDay();
407 }
408
409 /**
410 * Sets start of the month in the current dateTime
411 *
412 * @return self
413 */
414 public function startOfMonth()
415 {
416 return $this->modify('first day of this month')->startOfDay();
417 }
418
419 /**
420 * Sets end of the month in the current dateTime
421 *
422 * @return self
423 */
424 public function endOfMonth()
425 {
426 return $this->modify('last day of this month')->endOfDay();
427 }
428
429 /**
430 * Sets start of the week in the current dateTime
431 *
432 * @return self
433 */
434 public function startOfWeek()
435 {
436 $startOfWeek = intval(get_option('start_of_week'));
437
438 $this->modify('this week');
439
440 // If the start of the week is Sunday (0)
441 if ($startOfWeek === 0) {
442 return $this->modify('this Sunday')->startOfDay();
443 } else {
444 // If it's Monday (1), we need to subtract 1 day.
445 return $this->modify(
446 'this Sunday - ' . (7 - $startOfWeek) . ' days'
447 )->startOfDay();
448 }
449 }
450
451 /**
452 * Sets end of the week in the current dateTime
453 *
454 * @return self
455 */
456 public function endOfWeek()
457 {
458 // 0 = Sunday, 1 = Monday, etc.
459 $startOfWeek = intval(get_option('start_of_week'));
460
461 // Calculate the end of the week based on the starting day
462 if ($startOfWeek === 0) {
463 // Week starts on Sunday, so end is end of Saturday
464 return $this->modify('next Saturday')->endOfDay();
465 } else {
466 // Week starts on Monday, so end is end of Sunday
467 return $this->modify('next Sunday')->endOfDay();
468 }
469 }
470
471 /**
472 * Sets start of the day in the current dateTime
473 *
474 * @return self
475 */
476 public function startOfDay()
477 {
478 return $this->setTime(0, 0, 0, 0);
479 }
480
481 /**
482 * Sets end of the day in the current dateTime
483 *
484 * @return self
485 */
486 public function endOfDay()
487 {
488 return $this->setTime(23, 59, 59);
489 }
490
491 /**
492 * Sets start of the hour in the current DateTime object
493 *
494 * @return self
495 */
496 public function startOfHour()
497 {
498 return $this->setTime($this->format('H'), 0, 0, 0);
499 }
500
501 /**
502 * Sets end of the hour in the current DateTime object
503 *
504 * @return self
505 */
506 public function endOfHour()
507 {
508 return $this->setTime($this->format('H'), 59, 59, 999999);
509 }
510
511 /**
512 * Sets start of the minute in the current DateTime object
513 *
514 * @return self
515 */
516 public function startOfMinute()
517 {
518 $hour = $this->format('H');
519 $minute = $this->format('i');
520 return $this->setTime($hour, $minute, 0, 0);
521 }
522
523 /**
524 * Sets end of the minute in the current DateTime object
525 *
526 * @return self
527 */
528 public function endOfMinute()
529 {
530 $hour = $this->format('H');
531 $minute = $this->format('i');
532 return $this->setTime($hour, $minute, 59, 999999);
533 }
534
535 /**
536 * Check if the current instance is a weekend.
537 *
538 * @return bool
539 */
540 public function isWeekend()
541 {
542 // Get the day of the week: 0 (Sunday) to 6 (Saturday)
543 $dayOfWeek = (int) $this->format('w');
544 return ($dayOfWeek === 0 || $dayOfWeek === 6);
545 }
546
547 /**
548 * Check if the current instance is a weekday.
549 *
550 * @return bool
551 */
552 public function isWeekday()
553 {
554 return !$this->isWeekend();
555 }
556
557 /**
558 * Check if the current instance is in the past.
559 *
560 * @return bool
561 */
562 public function isPast()
563 {
564 // Compare with current date and time
565 return $this < new static();
566 }
567
568 /**
569 * Check if the current instance is in the future.
570 *
571 * @return bool
572 */
573 public function isFuture()
574 {
575 return $this > new static();
576 }
577
578 /**
579 * Check if the current instance is the same day as another DateTime instance.
580 *
581 * @param DateTime $other
582 * @return bool
583 */
584 public function isSameDay(DateTime $other)
585 {
586 return $this->format('Y-m-d') === $other->format('Y-m-d');
587 }
588
589 /**
590 * Clone the current Object
591 *
592 * @return \FluentCommunity\Framework\Support\DateTime
593 */
594 public function copy()
595 {
596 return clone $this;
597 }
598
599 /**
600 * Get the difference in years
601 *
602 * @param \FluentCommunity\Framework\Support\DateTime $date
603 * @return int
604 */
605 public function diffInYears($date)
606 {
607 return $this->diff($date)->y;
608 }
609
610 /**
611 * Get the difference in months
612 *
613 * @param \FluentCommunity\Framework\Support\DateTime $date
614 * @return int
615 */
616 public function diffInMonths($date)
617 {
618 $diff = $this->diff($date);
619
620 return $diff->y * 12 + $diff->m;
621 }
622
623 /**
624 * Get the difference in days
625 *
626 * @param \FluentCommunity\Framework\Support\DateTime $date
627 * @return int
628 */
629 public function diffInDays($date)
630 {
631 $diff = $this->diff($date);
632
633 return $diff->days;
634 }
635
636 /**
637 * Get the difference in hours
638 *
639 * @param \FluentCommunity\Framework\Support\DateTime $date
640 * @return int
641 */
642 public function diffInHours($date)
643 {
644 $diff = $this->diff($date);
645
646 $diffInHours = $diff->h;
647
648 return $diffInHours + $diff->days * 24;
649 }
650
651 /**
652 * Get the difference in minutes
653 *
654 * @param \FluentCommunity\Framework\Support\DateTime $date
655 * @return int
656 */
657 public function diffInMinutes($date)
658 {
659 $diff = $this->diff($date);
660
661 $diffInMinutes = $diff->i;
662
663 $diffInMinutes += $diff->h * 60;
664
665 return $diffInMinutes + $diff->days * 24 * 60;
666 }
667
668 /**
669 * Get the difference in seconds
670 *
671 * @param \FluentCommunity\Framework\Support\DateTime $date
672 * @return int
673 */
674 public function diffInSeconds($date)
675 {
676 $diff = $this->diff($date);
677
678 $diffInSeconds = $diff->days * 24 * 60 * 60;
679
680 $diffInSeconds += $diff->h * 60 * 60;
681
682 $diffInSeconds += $diff->i * 60;
683
684 return $diffInSeconds + $diff->s;
685 }
686
687 /**
688 * Get human friendly time difference (2 hours ago/ 2 hours from now)
689 *
690 * @param \DateTime|string|timestamp $from The datetime to compare from
691 * @param \DateTime|string|timestamp $to The datetime to compare to
692
693 * @return string Human readable string, ie. 5 days ago/from now
694 */
695 public function diffForHumans($from = null, $to = null)
696 {
697 // Use the current object's timestamp if $from (and $to) is null
698 // This is because ORM's datetime field can call it without params.
699 if (is_null($from)) {
700 $from = $this->getTimestamp();
701 } elseif ($from instanceof \DateTime) {
702 $from = $from->getTimestamp();
703 } elseif (!is_numeric($from)) {
704 $from = (new \DateTime($from))->getTimestamp();
705 }
706
707 // Use the current time as $to if not provided
708 if (is_null($to)) {
709 $to = time();
710 } elseif ($to instanceof \DateTime) {
711 $to = $to->getTimestamp();
712 } elseif (!is_numeric($to)) {
713 $to = (new \DateTime($to))->getTimestamp();
714 }
715
716 // Calculate the difference in seconds
717 $diffInSeconds = abs($to - $from);
718 $dateTimeDiff = human_time_diff($from, $to);
719
720 // Determine if the difference is in the past or future
721 if ($from > $to) {
722 // The "from" time is earlier than "to" (future)
723 return sprintf(__('%s from now'), $dateTimeDiff);
724 } else {
725 // The "from" time is later than "to" (older)
726 if ($diffInSeconds > 60) {
727 return sprintf(__('%s ago'), $dateTimeDiff);
728 }
729
730 // If difference is less than 1 minute, return just now
731 return __('just now');
732 }
733 }
734
735 /**
736 * Given a date in the timezone of the site, returns that date in UTC.
737 *
738 * Requires and returns a date in the Y-m-d H:i:s format.
739 *
740 * Return format can be overridden using the $format parameter.
741 *
742 * @param string $dateString The date to be converted, in the timezone of the site.
743 * @param string $format The format string for the returned date. Default 'Y-m-d H:i:s'.
744 * @see https://developer.wordpress.org/reference/functions/get_gmt_from_date/
745 *
746 * @return string Formatted version of the date, in UTC.
747 */
748 public function toUTC($dateString, $format = 'Y-m-d H:i:s')
749 {
750 return get_gmt_from_date($dateString, $format);
751 }
752
753 /**
754 * Return the ISO-8601 string
755 *
756 * @see https://stackoverflow.com/a/11173072/741747
757 *
758 * @return mixed
759 */
760 public function toJSON()
761 {
762 return date('c', $this->getTimestamp());
763 }
764
765 /**
766 * Returns the formatted string
767 *
768 * @return string
769 */
770 public function toString()
771 {
772 return (string) $this;
773 }
774
775 /**
776 * Return only the date part as string
777 *
778 * @return string
779 */
780 public function toDateString()
781 {
782 return (string) $this->format('Y-m-d');
783 }
784
785 /**
786 * Return only the time part as string
787 *
788 * @return string
789 */
790 public function toTimeString()
791 {
792 return (string) $this->format('H:i:s');
793 }
794
795 /**
796 * Returns the formatted string
797 *
798 * @return string
799 */
800 public function __toString()
801 {
802 return $this->format($this->getDateFormat());
803 }
804
805 /**
806 * Getter to get an unit of DateTime
807 * @param string $key
808 * @return string|null
809 */
810 public function __get($key)
811 {
812 if ($key == 'year') {
813 return $this->format('Y');
814 } elseif ($key == 'month') {
815 return $this->format('m');
816 } elseif ($key == 'day') {
817 return $this->format('d');
818 } elseif ($key == 'hour') {
819 return $this->format('H');
820 } elseif ($key == 'minute') {
821 return $this->format('i');
822 } elseif ($key == 'second') {
823 return $this->format('s');
824 }
825 }
826
827 /**
828 * Setter to set an unit of DateTime
829 * @param string $key
830 * @param string|int $value
831 * @return self
832 */
833 public function __set($key, $value)
834 {
835 if ($key == 'year') {
836 return $this->setDate($value, $this->format('m'), $this->format('d'));
837 } elseif ($key == 'month') {
838 return $this->setDate($this->format('Y'), $value, $this->format('d'));
839 } elseif ($key == 'day') {
840 return $this->setDate($this->format('Y'), $this->format('m'), $value);
841 } elseif ($key == 'hour') {
842 return $this->setTime($value, $this->format('i'), $this->format('s'));
843 } elseif ($key == 'minute') {
844 return $this->setTime($this->format('H'), $value, $this->format('s'));
845 } elseif ($key == 'second') {
846 return $this->setTime($this->format('H'), $this->format('i'), $value);
847 }
848 }
849
850 /**
851 * Handle Dynamic calls (add/sub)
852 *
853 * @param string $method
854 * @param array $params
855 * @return self
856 */
857 public function __call($method, $params)
858 {
859 // Dynamic Setter/Getter
860 if (strpos($method, 'set') === 0) {
861 $unit = strtolower(substr($method, 3));
862 if ($params && in_array($unit, static::$singularUnits)) {
863 $this->{$unit} = reset($params);
864 return $this;
865 }
866 } elseif (strpos($method, 'get') === 0) {
867 $unit = strtolower(substr($method, 3));
868 if (in_array($unit, static::$singularUnits)) {
869 return $this->{$unit};
870 }
871 }
872
873 // Dynamic adder/subtractor
874 if (strpos($method, 'add') === 0) {
875 $action = '+';
876 } elseif (strpos($method, 'sub') === 0) {
877 $action = '-';
878 }
879
880 if (isset($action) && in_array($action, ['+', '-'])) {
881
882 if (!$params) {
883 $duration = 1;
884 } else {
885 $duration = reset($params);
886 }
887
888
889 $unit = strtolower(substr($method, 3));
890
891 $units = array_merge(static::$singularUnits, static::$pluralUnits);
892
893 if (in_array($unit, $units)) {
894 return $this->modify("{$action}{$duration}{$unit}");
895 }
896 }
897
898 throw new InvalidArgumentException("Call to undefined method {$method}.");
899 }
900 }
901