PluginProbe
Fluent Booking – The Ultimate Appointments Scheduling, Events Booking, Events Calendar Solution / 1.5.21
Fluent Booking – The Ultimate Appointments Scheduling, Events Booking, Events Calendar Solution v1.5.21
2.4.0 2.3.0 2.2.5 2.2.0 2.1.2 2.1.1 trunk 1.10.0 1.10.01 1.10.02 1.5.0 1.5.01 1.5.02 1.5.1 1.5.10 1.5.20 1.5.21 1.5.22 1.5.23 1.5.24 1.5.25 1.6.0 1.7.0 1.7.1 1.7.2 All 33 releases
fluent-booking / vendor / wpfluent / framework / src / WPFluent / Support / DateTime.php

DateTime.php in Fluent Booking – The Ultimate Appointments Scheduling, Events Booking, Events Calendar Solution 1.5.21, at vendor/wpfluent/framework/src/WPFluent/Support/DateTime.php

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