diff --git a/alerts/class-alert-type-email.php b/alerts/class-alert-type-email.php index e4f09d09..1d1e0cc1 100644 --- a/alerts/class-alert-type-email.php +++ b/alerts/class-alert-type-email.php @@ -84,7 +84,7 @@ public function alert( $record_id, $recordarr, $alert ) { $user = get_user_by( 'id', $user_id ); // translators: Placeholder refers to a username (e.g. "administrator"). - $message .= sprintf( __( "User:\t%s", 'stream' ), $user->user_login ) . "\n"; + $message .= sprintf( __( "User:\t%s", 'stream' ), ! empty( $user->user_login ) ? $user->user_login : __( 'unknown', 'stream' ) ) . "\n"; if ( ! empty( $alert->alert_meta['trigger_context'] ) ) { $context = $this->plugin->alerts->alert_triggers['context']->get_display_value( 'list_table', $alert ); diff --git a/alerts/class-alert-type-ifttt.php b/alerts/class-alert-type-ifttt.php index 86996cde..971f19d0 100644 --- a/alerts/class-alert-type-ifttt.php +++ b/alerts/class-alert-type-ifttt.php @@ -216,20 +216,24 @@ public function notify_ifttt( $alert, $recordarr ) { ) ); - $user_id = $recordarr['user_id']; - $user = get_user_by( 'id', $user_id ); + $user_id = ! empty( $recordarr['user_id'] ) ? $recordarr['user_id'] : 0; + $user = get_user_by( 'id', $user_id ); + $user_value = ''; - /** - * Filter User data field - * - * Defaults to 'user_login'. - * - * @param object $alert The Alert. - * @param array $recordarray The Record's data. - * @return string - */ - $user_field = apply_filters( 'wp_stream_alert_ifttt_user_data_value', 'user_login', $alert, $recordarr ); - $user_value = ! empty( $user->$user_field ) ? $user->$user_field : $user->user_login; + if ( $user instanceof \WP_User ) { + /** + * Filter User data field. + * + * Defaults to 'user_login'. + * + * @param object $alert The Alert object. + * @param array $recordarr Array of Record data. + * + * @return string + */ + $user_field = apply_filters( 'wp_stream_alert_ifttt_user_data_value', 'user_login', $alert, $recordarr ); + $user_value = ! empty( $user->$user_field ) ? $user->$user_field : $user->user_login; + } $created = $recordarr['created']; /** diff --git a/classes/class-alert.php b/classes/class-alert.php index dccd2c6a..66743620 100644 --- a/classes/class-alert.php +++ b/classes/class-alert.php @@ -66,8 +66,9 @@ class Alert { /** * Class constructor * - * @param object $item Alert data. - * @param Plugin $plugin Instance of plugin object. + * @param ?object $item Alert data. + * @param Plugin $plugin Instance of plugin object. + * * @return void */ public function __construct( $item, $plugin ) { diff --git a/classes/class-alerts.php b/classes/class-alerts.php index 45d600fc..ef753f28 100644 --- a/classes/class-alerts.php +++ b/classes/class-alerts.php @@ -410,18 +410,19 @@ public function register_post_type() { /** * Return alert object of the given ID * - * @param string $post_id Post ID for the alert. + * @param string|int $post_id Post ID for the alert. * * @return Alert */ public function get_alert( $post_id = '' ) { if ( ! $post_id ) { - $obj = new Alert( null, $this->plugin ); - - return $obj; + return new Alert( null, $this->plugin ); } $post = get_post( $post_id ); + if ( ! ( $post instanceof \WP_Post ) ) { + return new Alert( null, $this->plugin ); + } $alert_type = get_post_meta( $post_id, 'alert_type', true ); $alert_meta = get_post_meta( $post_id, 'alert_meta', true ); @@ -565,7 +566,7 @@ public function load_alerts_settings() { } $alert = array(); $post_id = wp_stream_filter_input( INPUT_POST, 'post_id' ); - if ( ! empty( $post_id ) ) { + if ( ! empty( $post_id ) && 'new' !== $post_id ) { $alert = $this->get_alert( $post_id ); if ( false === $alert ) { wp_send_json_error( diff --git a/classes/class-date-interval.php b/classes/class-date-interval.php index 25ccafac..9017c226 100644 --- a/classes/class-date-interval.php +++ b/classes/class-date-interval.php @@ -7,12 +7,6 @@ namespace WP_Stream; -// Load Carbon to Handle dates much easier. -if ( ! class_exists( 'Carbon\Carbon' ) ) { - require_once wp_stream_get_instance()->locations['inc_dir'] . 'lib/Carbon.php'; -} -use Carbon\Carbon; - /** * Class - Date_Interval */ @@ -43,86 +37,109 @@ public function get_predefined_intervals() { if ( empty( $timezone ) ) { $gmt_offset = (int) get_option( 'gmt_offset' ); - $timezone = timezone_name_from_abbr( null, $gmt_offset * 3600, true ); - if ( false === $timezone ) { - $timezone = timezone_name_from_abbr( null, $gmt_offset * 3600, false ); - } + $timezone = timezone_name_from_abbr( '', $gmt_offset * 3600, true ); if ( false === $timezone ) { - $timezone = null; + $timezone = timezone_name_from_abbr( '', $gmt_offset * 3600, false ); } } - return apply_filters( - 'wp_stream_predefined_date_intervals', - array( - 'today' => array( - 'label' => esc_html__( 'Today', 'stream' ), - 'start' => Carbon::today( $timezone )->startOfDay(), - 'end' => Carbon::today( $timezone )->endOfDay(), - ), - 'yesterday' => array( - 'label' => esc_html__( 'Yesterday', 'stream' ), - 'start' => Carbon::today( $timezone )->startOfDay()->subDay(), - 'end' => Carbon::today( $timezone )->startOfDay()->subSecond(), - ), - 'last-7-days' => array( - /* translators: %d: number of days (e.g. "7") */ - 'label' => sprintf( esc_html__( 'Last %d Days', 'stream' ), 7 ), - 'start' => Carbon::today( $timezone )->subDays( 7 ), - 'end' => Carbon::today( $timezone ), - ), - 'last-14-days' => array( - /* translators: %d: number of days (e.g. "7") */ - 'label' => sprintf( esc_html__( 'Last %d Days', 'stream' ), 14 ), - 'start' => Carbon::today( $timezone )->subDays( 14 ), - 'end' => Carbon::today( $timezone ), - ), - 'last-30-days' => array( - /* translators: %d: number of days (e.g. "7") */ - 'label' => sprintf( esc_html__( 'Last %d Days', 'stream' ), 30 ), - 'start' => Carbon::today( $timezone )->subDays( 30 ), - 'end' => Carbon::today( $timezone ), - ), - 'this-month' => array( - 'label' => esc_html__( 'This Month', 'stream' ), - 'start' => Carbon::today( $timezone )->startOfMonth(), - 'end' => Carbon::today( $timezone )->endOfMonth(), - ), - 'last-month' => array( - 'label' => esc_html__( 'Last Month', 'stream' ), - 'start' => Carbon::today( $timezone )->startOfMonth()->subMonth(), - 'end' => Carbon::today( $timezone )->startOfMonth()->subSecond(), - ), - 'last-3-months' => array( - /* translators: %d: number of months (e.g. "3") */ - 'label' => sprintf( esc_html__( 'Last %d Months', 'stream' ), 3 ), - 'start' => Carbon::today( $timezone )->subMonths( 3 ), - 'end' => Carbon::today( $timezone ), - ), - 'last-6-months' => array( - /* translators: %d: number of months (e.g. "3") */ - 'label' => sprintf( esc_html__( 'Last %d Months', 'stream' ), 6 ), - 'start' => Carbon::today( $timezone )->subMonths( 6 ), - 'end' => Carbon::today( $timezone ), - ), - 'last-12-months' => array( - /* translators: %d: number of months (e.g. "3") */ - 'label' => sprintf( esc_html__( 'Last %d Months', 'stream' ), 12 ), - 'start' => Carbon::today( $timezone )->subMonths( 12 ), - 'end' => Carbon::today( $timezone ), - ), - 'this-year' => array( - 'label' => esc_html__( 'This Year', 'stream' ), - 'start' => Carbon::today( $timezone )->startOfYear(), - 'end' => Carbon::today( $timezone )->endOfYear(), - ), - 'last-year' => array( - 'label' => esc_html__( 'Last Year', 'stream' ), - 'start' => Carbon::today( $timezone )->startOfYear()->subYear(), - 'end' => Carbon::today( $timezone )->startOfYear()->subSecond(), - ), + try { + $timezone_object = $timezone ? new \DateTimeZone( $timezone ) : null; + } catch ( \Exception $e ) { + $timezone_object = null; + } + + try { + $today = new \DateTimeImmutable( 'today', $timezone_object ); + $date_intervals = $this->generate_date_intervals( $today ); + } catch ( \Exception $e ) { + $date_intervals = array(); + } + + /** + * Allow other plugins to filter the predefined date intervals. + * + * @param array $date_intervals Date intervals array. + * @param string $timezone Timezone. + */ + return apply_filters( 'wp_stream_predefined_date_intervals', $date_intervals, $timezone ); + } + + /** + * Generate date intervals relative to date object provided. + * + * @param \DateTimeImmutable $date Date object. + * + * @return array[] + */ + public function generate_date_intervals( \DateTimeImmutable $date ) { + return array( + 'today' => array( + 'label' => esc_html__( 'Today', 'stream' ), + 'start' => $date, + 'end' => $date->modify( '+1 day -1 microsecond' ), + ), + 'yesterday' => array( + 'label' => esc_html__( 'Yesterday', 'stream' ), + 'start' => $date->modify( '-1 day' ), + 'end' => $date->modify( '-1 microsecond' ), + ), + 'last-7-days' => array( + /* translators: %d: number of days (e.g. "7") */ + 'label' => sprintf( esc_html__( 'Last %d Days', 'stream' ), 7 ), + 'start' => $date->modify( '-7 days' ), + 'end' => $date, + ), + 'last-14-days' => array( + /* translators: %d: number of days (e.g. "7") */ + 'label' => sprintf( esc_html__( 'Last %d Days', 'stream' ), 14 ), + 'start' => $date->modify( '-14 days' ), + 'end' => $date, + ), + 'last-30-days' => array( + /* translators: %d: number of days (e.g. "7") */ + 'label' => sprintf( esc_html__( 'Last %d Days', 'stream' ), 30 ), + 'start' => $date->modify( '-30 days' ), + 'end' => $date, + ), + 'this-month' => array( + 'label' => esc_html__( 'This Month', 'stream' ), + 'start' => $date->modify( 'first day of this month' ), + 'end' => $date->modify( 'last day of this month' )->modify( '+1 day -1 microsecond' ), + ), + 'last-month' => array( + 'label' => esc_html__( 'Last Month', 'stream' ), + 'start' => $date->modify( 'first day of last month' ), + 'end' => $date->modify( 'last day of last month' )->modify( '+1 day -1 microsecond' ), + ), + 'last-3-months' => array( + /* translators: %d: number of months (e.g. "3") */ + 'label' => sprintf( esc_html__( 'Last %d Months', 'stream' ), 3 ), + 'start' => $date->modify( '-3 months' ), + 'end' => $date, + ), + 'last-6-months' => array( + /* translators: %d: number of months (e.g. "3") */ + 'label' => sprintf( esc_html__( 'Last %d Months', 'stream' ), 6 ), + 'start' => $date->modify( '-6 months' ), + 'end' => $date, + ), + 'last-12-months' => array( + /* translators: %d: number of months (e.g. "3") */ + 'label' => sprintf( esc_html__( 'Last %d Months', 'stream' ), 12 ), + 'start' => $date->modify( '-12 months' ), + 'end' => $date, + ), + 'this-year' => array( + 'label' => esc_html__( 'This Year', 'stream' ), + 'start' => $date->modify( 'first day of January' ), + 'end' => $date->modify( 'last day of December' )->modify( '+1 day -1 microsecond' ), + ), + 'last-year' => array( + 'label' => esc_html__( 'Last Year', 'stream' ), + 'start' => $date->modify( 'first day of January' )->modify( '-1 year' ), + 'end' => $date->modify( 'first day of January' )->modify( '-1 microsecond' ), ), - $timezone ); } } diff --git a/composer.json b/composer.json index fa36e4d7..490feaf2 100644 --- a/composer.json +++ b/composer.json @@ -19,6 +19,7 @@ "automattic/vipwpcs": "^3.0", "dealerdirect/phpcodesniffer-composer-installer": "^0.7.2", "humanmade/mercator": "^1.0", + "johnbillion/query-monitor": "^3.16", "php-coveralls/php-coveralls": "^2.5", "phpcompatibility/php-compatibility": "dev-develop as 9.99.99", "phpcompatibility/phpcompatibility-wp": "^2.1", diff --git a/composer.lock b/composer.lock index d15c067c..90ccd0fd 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "735291b73e1d9e13c7c854fbfdd74ca3", + "content-hash": "fd668c606b74fb123c6ffacceeff3e24", "packages": [ { "name": "composer/installers", @@ -1566,6 +1566,77 @@ }, "time": "2018-10-30T18:53:20+00:00" }, + { + "name": "johnbillion/query-monitor", + "version": "3.16.3", + "source": { + "type": "git", + "url": "https://github.com/johnbillion/query-monitor.git", + "reference": "6365775bbafcb024d70db557aa9d13539546b7ec" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/johnbillion/query-monitor/zipball/6365775bbafcb024d70db557aa9d13539546b7ec", + "reference": "6365775bbafcb024d70db557aa9d13539546b7ec", + "shasum": "" + }, + "require": { + "composer/installers": "^1.0 || ^2.0", + "php": ">=7.4.0" + }, + "require-dev": { + "codeception/module-asserts": "^1.0", + "codeception/module-db": "^1.0", + "codeception/module-webdriver": "^1.0", + "codeception/util-universalframework": "^1.0", + "dealerdirect/phpcodesniffer-composer-installer": "0.7.2", + "johnbillion/plugin-infrastructure": "dev-trunk", + "lucatume/wp-browser": "3.2.1", + "phpcompatibility/phpcompatibility-wp": "2.1.4", + "phpstan/phpstan": "1.10.39", + "phpstan/phpstan-phpunit": "1.3.15", + "roots/wordpress-core-installer": "1.100.0", + "roots/wordpress-full": "*", + "squizlabs/php_codesniffer": "3.7.1", + "szepeviktor/phpstan-wordpress": "1.3.0", + "wp-coding-standards/wpcs": "2.3.0" + }, + "type": "wordpress-plugin", + "extra": { + "wordpress-install-dir": "vendor/wordpress/wordpress" + }, + "autoload": { + "classmap": [ + "classes", + "data", + "output" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "GPL-2.0-or-later" + ], + "authors": [ + { + "name": "John Blackbourn", + "homepage": "https://johnblackbourn.com/" + } + ], + "description": "The Developer Tools panel for WordPress.", + "homepage": "https://github.com/johnbillion/query-monitor/", + "support": { + "forum": "https://wordpress.org/support/plugin/query-monitor", + "issues": "https://github.com/johnbillion/query-monitor/issues", + "source": "https://github.com/johnbillion/query-monitor" + }, + "funding": [ + { + "url": "https://github.com/sponsors/johnbillion", + "type": "github" + } + ], + "time": "2024-05-22T21:59:51+00:00" + }, { "name": "justinrainbow/json-schema", "version": "5.3.0", diff --git a/connectors/class-connector-acf.php b/connectors/class-connector-acf.php index f4e4107a..c278e729 100644 --- a/connectors/class-connector-acf.php +++ b/connectors/class-connector-acf.php @@ -614,7 +614,7 @@ public function check_meta_values( $type, $action, $meta_id, $object_id, $key, $ /* translators: %1$s: a field label, %2$s: an object title, %3$s: an object type (e.g. "Message", "Hello World", "post") */ esc_html_x( '"%1$s" of "%2$s" %3$s updated', 'acf', 'stream' ), array( - 'field_label' => $cache['field']['label'], + 'field_label' => ! empty( $cache['field']['label'] ) ? $cache['field']['label'] : __( 'unknown', 'stream' ), 'title' => $title, 'singular_name' => $type_name, 'meta_value' => $value, diff --git a/connectors/class-connector-jetpack.php b/connectors/class-connector-jetpack.php index 80a96587..d11492d7 100644 --- a/connectors/class-connector-jetpack.php +++ b/connectors/class-connector-jetpack.php @@ -373,15 +373,18 @@ public function callback_jetpack_log_entry( array $entry ) { } $user = new \WP_User( $user_id ); - $user_email = $user->user_email; - $user_login = $user->user_login; - $context = 'users'; - $action = $method; - $meta = compact( 'user_id', 'user_email', 'user_login' ); - $message = sprintf( - /* translators: %1$s: a user display name, %2$s: a status and the connection either "from" or "to" (e.g. "Jane Doe", "unlinked from") */ + $user_email = ! empty( $user->user_email ) ? $user->user_email : ''; + $user_login = ! empty( $user->user_login ) ? $user->user_login : ''; + + /* translators: %d is the user ID */ + $user_display_name = ! empty( $user->display_name ) ? $user->display_name : sprintf( __( 'Unknown user %d', 'stream' ), $user_id ); + $context = 'users'; + $action = $method; + $meta = compact( 'user_id', 'user_email', 'user_login' ); + $message = sprintf( + /* translators: %1$s: a user display name, %2$s: a status and the connection either "from" or "to" (e.g. "Jane Doe", "unlinked from") */ __( '%1$s\'s account %2$s Jetpack', 'stream' ), - $user->display_name, + $user_display_name, ( 'unlink' === $action ) ? esc_html__( 'unlinked from', 'stream' ) : esc_html__( 'linked to', 'stream' ) ); } elseif ( in_array( $method, array( 'register', 'disconnect', 'subsiteregister', 'subsitedisconnect' ), true ) ) { diff --git a/includes/lib/Carbon.php b/includes/lib/Carbon.php deleted file mode 100644 index bf62c031..00000000 --- a/includes/lib/Carbon.php +++ /dev/null @@ -1,2195 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Carbon; - -use Closure; -use DateTime; -use DateTimeZone; -use DateInterval; -use DatePeriod; -use InvalidArgumentException; - -/** - * A simple API extension for DateTime - * - * @property integer $year - * @property integer $month - * @property integer $day - * @property integer $hour - * @property integer $minute - * @property integer $second - * @property integer $timestamp seconds since the Unix Epoch - * @property-read integer $micro - * @property-read integer $dayOfWeek 0 (for Sunday) through 6 (for Saturday) - * @property-read integer $dayOfYear 0 through 365 - * @property-read integer $weekOfMonth 1 through 6 - * @property-read integer $weekOfYear ISO-8601 week number of year, weeks starting on Monday - * @property-read integer $daysInMonth number of days in the given month - * @property-read integer $age does a diffInYears() with default parameters - * @property-read integer $quarter the quarter of this instance, 1 - 4 - * @property-read integer $offset the timezone offset in seconds from UTC - * @property-read integer $offsetHours the timezone offset in hours from UTC - * @property-read boolean $dst daylight savings time indicator, true if DST, false otherwise - * @property-read boolean $local checks if the timezone is local, true if local, false otherwise - * @property-read boolean $utc checks if the timezone is UTC, true if UTC, false otherwise - * @property-read string $timezoneName - * @property-read string $tzName - * - * @property-read DateTimeZone $timezone the current timezone - * @property-read DateTimeZone $tz alias of timezone - * @property-write DateTimeZone|string $timezone the current timezone - * @property-write DateTimeZone|string $tz alias of timezone - * - */ -class Carbon extends DateTime -{ - /** - * The day constants - */ - const SUNDAY = 0; - const MONDAY = 1; - const TUESDAY = 2; - const WEDNESDAY = 3; - const THURSDAY = 4; - const FRIDAY = 5; - const SATURDAY = 6; - - /** - * Names of days of the week. - * - * @var array - */ - protected static $days = array( - self::SUNDAY => 'Sunday', - self::MONDAY => 'Monday', - self::TUESDAY => 'Tuesday', - self::WEDNESDAY => 'Wednesday', - self::THURSDAY => 'Thursday', - self::FRIDAY => 'Friday', - self::SATURDAY => 'Saturday' - ); - - /** - * Terms used to detect if a time passed is a relative date for testing purposes - * - * @var array - */ - protected static $relativeKeywords = array( - 'this', - 'next', - 'last', - 'tomorrow', - 'yesterday', - '+', - '-', - 'first', - 'last', - 'ago' - ); - - /** - * Number of X in Y - */ - const YEARS_PER_CENTURY = 100; - const YEARS_PER_DECADE = 10; - const MONTHS_PER_YEAR = 12; - const WEEKS_PER_YEAR = 52; - const DAYS_PER_WEEK = 7; - const HOURS_PER_DAY = 24; - const MINUTES_PER_HOUR = 60; - const SECONDS_PER_MINUTE = 60; - - /** - * Default format to use for __toString method when type juggling occurs. - * - * @var string - */ - const DEFAULT_TO_STRING_FORMAT = 'Y-m-d H:i:s'; - - /** - * Format to use for __toString method when type juggling occurs. - * - * @var string - */ - protected static $toStringFormat = self::DEFAULT_TO_STRING_FORMAT; - - /** - * A test Carbon instance to be returned when now instances are created - * - * @var Carbon - */ - protected static $testNow; - - /** - * Creates a DateTimeZone from a string or a DateTimeZone - * - * @param DateTimeZone|string $object - * - * @return DateTimeZone - * - * @throws InvalidArgumentException - */ - protected static function safeCreateDateTimeZone($object) - { - if ($object instanceof DateTimeZone) { - return $object; - } - - $tz = @timezone_open((string) $object); - - if ($tz === false) { - throw new InvalidArgumentException('Unknown or bad timezone ('.$object.')'); - } - - return $tz; - } - - /////////////////////////////////////////////////////////////////// - //////////////////////////// CONSTRUCTORS ///////////////////////// - /////////////////////////////////////////////////////////////////// - - /** - * Create a new Carbon instance. - * - * Please see the testing aids section (specifically static::setTestNow()) - * for more on the possibility of this constructor returning a test instance. - * - * @param string $time - * @param DateTimeZone|string $tz - */ - public function __construct($time = null, $tz = null) - { - // If the class has a test now set and we are trying to create a now() - // instance then override as required - if (static::hasTestNow() && (empty($time) || $time === 'now' || static::hasRelativeKeywords($time))) { - $testInstance = clone static::getTestNow(); - if (static::hasRelativeKeywords($time)) { - $testInstance->modify($time); - } - - //shift the time according to the given time zone - if ($tz !== NULL && $tz != static::getTestNow()->tz) { - $testInstance->setTimezone($tz); - } else { - $tz = $testInstance->tz; - } - - $time = $testInstance->toDateTimeString(); - } - - if ($tz !== null) { - parent::__construct($time, static::safeCreateDateTimeZone($tz)); - } else { - parent::__construct($time); - } - } - - /** - * Create a Carbon instance from a DateTime one - * - * @param DateTime $dt - * - * @return static - */ - public static function instance(DateTime $dt) - { - return new static($dt->format('Y-m-d H:i:s.u'), $dt->getTimeZone()); - } - - /** - * Create a carbon instance from a string. This is an alias for the - * constructor that allows better fluent syntax as it allows you to do - * Carbon::parse('Monday next week')->fn() rather than - * (new Carbon('Monday next week'))->fn() - * - * @param string $time - * @param DateTimeZone|string $tz - * - * @return static - */ - public static function parse($time = null, $tz = null) - { - return new static($time, $tz); - } - - /** - * Get a Carbon instance for the current date and time - * - * @param DateTimeZone|string $tz - * - * @return static - */ - public static function now($tz = null) - { - return new static(null, $tz); - } - - /** - * Create a Carbon instance for today - * - * @param DateTimeZone|string $tz - * - * @return static - */ - public static function today($tz = null) - { - return static::now($tz)->startOfDay(); - } - - /** - * Create a Carbon instance for tomorrow - * - * @param DateTimeZone|string $tz - * - * @return static - */ - public static function tomorrow($tz = null) - { - return static::today($tz)->addDay(); - } - - /** - * Create a Carbon instance for yesterday - * - * @param DateTimeZone|string $tz - * - * @return static - */ - public static function yesterday($tz = null) - { - return static::today($tz)->subDay(); - } - - /** - * Create a Carbon instance for the greatest supported date. - * - * @return Carbon - */ - public static function maxValue() - { - return static::createFromTimestamp(PHP_INT_MAX); - } - - /** - * Create a Carbon instance for the lowest supported date. - * - * @return Carbon - */ - public static function minValue() - { - return static::createFromTimestamp(~PHP_INT_MAX); - } - - /** - * Create a new Carbon instance from a specific date and time. - * - * If any of $year, $month or $day are set to null their now() values - * will be used. - * - * If $hour is null it will be set to its now() value and the default values - * for $minute and $second will be their now() values. - * If $hour is not null then the default values for $minute and $second - * will be 0. - * - * @param integer $year - * @param integer $month - * @param integer $day - * @param integer $hour - * @param integer $minute - * @param integer $second - * @param DateTimeZone|string $tz - * - * @return static - */ - public static function create($year = null, $month = null, $day = null, $hour = null, $minute = null, $second = null, $tz = null) - { - $year = ($year === null) ? gmdate('Y') : $year; - $month = ($month === null) ? gmdate('n') : $month; - $day = ($day === null) ? gmdate('j') : $day; - - if ($hour === null) { - $hour = gmdate('G'); - $minute = ($minute === null) ? gmdate('i') : $minute; - $second = ($second === null) ? gmdate('s') : $second; - } else { - $minute = ($minute === null) ? 0 : $minute; - $second = ($second === null) ? 0 : $second; - } - - return static::createFromFormat('Y-n-j G:i:s', sprintf('%s-%s-%s %s:%02s:%02s', $year, $month, $day, $hour, $minute, $second), $tz); - } - - /** - * Create a Carbon instance from just a date. The time portion is set to now. - * - * @param integer $year - * @param integer $month - * @param integer $day - * @param DateTimeZone|string $tz - * - * @return static - */ - public static function createFromDate($year = null, $month = null, $day = null, $tz = null) - { - return static::create($year, $month, $day, null, null, null, $tz); - } - - /** - * Create a Carbon instance from just a time. The date portion is set to today. - * - * @param integer $hour - * @param integer $minute - * @param integer $second - * @param DateTimeZone|string $tz - * - * @return static - */ - public static function createFromTime($hour = null, $minute = null, $second = null, $tz = null) - { - return static::create(null, null, null, $hour, $minute, $second, $tz); - } - - /** - * Create a Carbon instance from a specific format - * - * @param string $format - * @param string $time - * @param DateTimeZone|string $tz - * - * @return static - * - * @throws InvalidArgumentException - */ - public static function createFromFormat($format, $time, $tz = null) - { - if ($tz !== null) { - $dt = parent::createFromFormat($format, $time, static::safeCreateDateTimeZone($tz)); - } else { - $dt = parent::createFromFormat($format, $time); - } - - if ($dt instanceof DateTime) { - return static::instance($dt); - } - - $errors = static::getLastErrors(); - throw new InvalidArgumentException(implode(PHP_EOL, $errors['errors'])); - } - - /** - * Create a Carbon instance from a timestamp - * - * @param integer $timestamp - * @param DateTimeZone|string $tz - * - * @return static - */ - public static function createFromTimestamp($timestamp, $tz = null) - { - return static::now($tz)->setTimestamp($timestamp); - } - - /** - * Create a Carbon instance from an UTC timestamp - * - * @param integer $timestamp - * - * @return static - */ - public static function createFromTimestampUTC($timestamp) - { - return new static('@'.$timestamp); - } - - /** - * Get a copy of the instance - * - * @return static - */ - public function copy() - { - return static::instance($this); - } - - /////////////////////////////////////////////////////////////////// - ///////////////////////// GETTERS AND SETTERS ///////////////////// - /////////////////////////////////////////////////////////////////// - - /** - * Get a part of the Carbon object - * - * @param string $name - * - * @throws InvalidArgumentException - * - * @return string|integer|DateTimeZone - */ - public function __get($name) - { - switch ($name) { - case 'year': - case 'month': - case 'day': - case 'hour': - case 'minute': - case 'second': - case 'micro': - case 'dayOfWeek': - case 'dayOfYear': - case 'weekOfYear': - case 'daysInMonth': - case 'timestamp': - $formats = array( - 'year' => 'Y', - 'month' => 'n', - 'day' => 'j', - 'hour' => 'G', - 'minute' => 'i', - 'second' => 's', - 'micro' => 'u', - 'dayOfWeek' => 'w', - 'dayOfYear' => 'z', - 'weekOfYear' => 'W', - 'daysInMonth' => 't', - 'timestamp' => 'U', - ); - - return (int) $this->format($formats[$name]); - - case 'weekOfMonth': - return (int) ceil($this->day / self::DAYS_PER_WEEK); - - case 'age': - return (int) $this->diffInYears(); - - case 'quarter': - return (int) ceil($this->month / 3); - - case 'offset': - return $this->getOffset(); - - case 'offsetHours': - return $this->getOffset() / self::SECONDS_PER_MINUTE / self::MINUTES_PER_HOUR; - - case 'dst': - return $this->format('I') == '1'; - - case 'local': - return $this->offset == $this->copy()->setTimezone(date_default_timezone_get())->offset; - - case 'utc': - return $this->offset == 0; - - case 'timezone': - case 'tz': - return $this->getTimezone(); - - case 'timezoneName': - case 'tzName': - return $this->getTimezone()->getName(); - - default: - throw new InvalidArgumentException(sprintf("Unknown getter '%s'", $name)); - } - } - - /** - * Check if an attribute exists on the object - * - * @param string $name - * - * @return boolean - */ - public function __isset($name) - { - try { - $this->__get($name); - } catch (InvalidArgumentException $e) { - return false; - } - - return true; - } - - /** - * Set a part of the Carbon object - * - * @param string $name - * @param string|integer|DateTimeZone $value - * - * @throws InvalidArgumentException - */ - public function __set($name, $value) - { - switch ($name) { - case 'year': - parent::setDate($value, $this->month, $this->day); - break; - - case 'month': - parent::setDate($this->year, $value, $this->day); - break; - - case 'day': - parent::setDate($this->year, $this->month, $value); - break; - - case 'hour': - parent::setTime($value, $this->minute, $this->second); - break; - - case 'minute': - parent::setTime($this->hour, $value, $this->second); - break; - - case 'second': - parent::setTime($this->hour, $this->minute, $value); - break; - - case 'timestamp': - parent::setTimestamp($value); - break; - - case 'timezone': - case 'tz': - $this->setTimezone($value); - break; - - default: - throw new InvalidArgumentException(sprintf("Unknown setter '%s'", $name)); - } - } - - /** - * Set the instance's year - * - * @param integer $value - * - * @return static - */ - public function year($value) - { - $this->year = $value; - - return $this; - } - - /** - * Set the instance's month - * - * @param integer $value - * - * @return static - */ - public function month($value) - { - $this->month = $value; - - return $this; - } - - /** - * Set the instance's day - * - * @param integer $value - * - * @return static - */ - public function day($value) - { - $this->day = $value; - - return $this; - } - - /** - * Set the date all together - * - * @param integer $year - * @param integer $month - * @param integer $day - * - * @return static - */ - public function setDate($year, $month, $day) - { - parent::setDate($year, $month, $day); - - return $this; - } - - /** - * Set the instance's hour - * - * @param integer $value - * - * @return static - */ - public function hour($value) - { - $this->hour = $value; - - return $this; - } - - /** - * Set the instance's minute - * - * @param integer $value - * - * @return static - */ - public function minute($value) - { - $this->minute = $value; - - return $this; - } - - /** - * Set the instance's second - * - * @param integer $value - * - * @return static - */ - public function second($value) - { - $this->second = $value; - - return $this; - } - - /** - * Set the time all together - * - * @param integer $hour - * @param integer $minute - * @param integer $second - * @param integer $microseconds - * - * @return static - */ - public function setTime($hour, $minute, $second = 0, $microseconds = 0 ) - { - parent::setTime($hour, $minute, $second, $microseconds ); - - return $this; - } - - /** - * Set the date and time all together - * - * @param integer $year - * @param integer $month - * @param integer $day - * @param integer $hour - * @param integer $minute - * @param integer $second - * - * @return static - */ - public function setDateTime($year, $month, $day, $hour, $minute, $second = 0) - { - return $this->setDate($year, $month, $day)->setTime($hour, $minute, $second); - } - - /** - * Set the instance's timestamp - * - * @param integer $value - * - * @return static - */ - public function timestamp($value) - { - $this->timestamp = $value; - - return $this; - } - - /** - * Alias for setTimezone() - * - * @param DateTimeZone|string $value - * - * @return static - */ - public function timezone($value) - { - return $this->setTimezone($value); - } - - /** - * Alias for setTimezone() - * - * @param DateTimeZone|string $value - * - * @return static - */ - public function tz($value) - { - return $this->setTimezone($value); - } - - /** - * Set the instance's timezone from a string or object - * - * @param DateTimeZone|string $value - * - * @return static - */ - public function setTimezone($value) - { - parent::setTimezone(static::safeCreateDateTimeZone($value)); - - return $this; - } - - /////////////////////////////////////////////////////////////////// - ///////////////////////// TESTING AIDS //////////////////////////// - /////////////////////////////////////////////////////////////////// - - /** - * Set a Carbon instance (real or mock) to be returned when a "now" - * instance is created. The provided instance will be returned - * specifically under the following conditions: - * - A call to the static now() method, ex. Carbon::now() - * - When a null (or blank string) is passed to the constructor or parse(), ex. new Carbon(null) - * - When the string "now" is passed to the constructor or parse(), ex. new Carbon('now') - * - * Note the timezone parameter was left out of the examples above and - * has no affect as the mock value will be returned regardless of its value. - * - * To clear the test instance call this method using the default - * parameter of null. - * - * @param Carbon $testNow - */ - public static function setTestNow(Carbon $testNow = null) - { - static::$testNow = $testNow; - } - - /** - * Get the Carbon instance (real or mock) to be returned when a "now" - * instance is created. - * - * @return static the current instance used for testing - */ - public static function getTestNow() - { - return static::$testNow; - } - - /** - * Determine if there is a valid test instance set. A valid test instance - * is anything that is not null. - * - * @return boolean true if there is a test instance, otherwise false - */ - public static function hasTestNow() - { - return static::getTestNow() !== null; - } - - /** - * Determine if there is a relative keyword in the time string, this is to - * create dates relative to now for test instances. e.g.: next tuesday - * - * @param string $time - * - * @return boolean true if there is a keyword, otherwise false - */ - public static function hasRelativeKeywords($time) - { - // skip common format with a '-' in it - if (preg_match('/[0-9]{4}-[0-9]{1,2}-[0-9]{1,2}/', $time) !== 1) { - foreach (static::$relativeKeywords as $keyword) { - if (stripos($time, $keyword) !== false) { - return true; - } - } - } - - return false; - } - - /////////////////////////////////////////////////////////////////// - /////////////////////// STRING FORMATTING ///////////////////////// - /////////////////////////////////////////////////////////////////// - - /** - * Reset the format used to the default when type juggling a Carbon instance to a string - * - */ - public static function resetToStringFormat() - { - static::setToStringFormat(self::DEFAULT_TO_STRING_FORMAT); - } - - /** - * Set the default format used when type juggling a Carbon instance to a string - * - * @param string $format - */ - public static function setToStringFormat($format) - { - static::$toStringFormat = $format; - } - - /** - * Format the instance as a string using the set format - * - * @return string - */ - public function __toString() - { - return $this->format(static::$toStringFormat); - } - - /** - * Format the instance as date - * - * @return string - */ - public function toDateString() - { - return $this->format('Y-m-d'); - } - - /** - * Format the instance as a readable date - * - * @return string - */ - public function toFormattedDateString() - { - return $this->format('M j, Y'); - } - - /** - * Format the instance as time - * - * @return string - */ - public function toTimeString() - { - return $this->format('H:i:s'); - } - - /** - * Format the instance as date and time - * - * @return string - */ - public function toDateTimeString() - { - return $this->format('Y-m-d H:i:s'); - } - - /** - * Format the instance with day, date and time - * - * @return string - */ - public function toDayDateTimeString() - { - return $this->format('D, M j, Y g:i A'); - } - - /** - * Format the instance as ATOM - * - * @return string - */ - public function toAtomString() - { - return $this->format(self::ATOM); - } - - /** - * Format the instance as COOKIE - * - * @return string - */ - public function toCookieString() - { - return $this->format(self::COOKIE); - } - - /** - * Format the instance as ISO8601 - * - * @return string - */ - public function toIso8601String() - { - return $this->format(self::ISO8601); - } - - /** - * Format the instance as RFC822 - * - * @return string - */ - public function toRfc822String() - { - return $this->format(self::RFC822); - } - - /** - * Format the instance as RFC850 - * - * @return string - */ - public function toRfc850String() - { - return $this->format(self::RFC850); - } - - /** - * Format the instance as RFC1036 - * - * @return string - */ - public function toRfc1036String() - { - return $this->format(self::RFC1036); - } - - /** - * Format the instance as RFC1123 - * - * @return string - */ - public function toRfc1123String() - { - return $this->format(self::RFC1123); - } - - /** - * Format the instance as RFC2822 - * - * @return string - */ - public function toRfc2822String() - { - return $this->format(self::RFC2822); - } - - /** - * Format the instance as RFC3339 - * - * @return string - */ - public function toRfc3339String() - { - return $this->format(self::RFC3339); - } - - /** - * Format the instance as RSS - * - * @return string - */ - public function toRssString() - { - return $this->format(self::RSS); - } - - /** - * Format the instance as W3C - * - * @return string - */ - public function toW3cString() - { - return $this->format(self::W3C); - } - - /////////////////////////////////////////////////////////////////// - ////////////////////////// COMPARISONS //////////////////////////// - /////////////////////////////////////////////////////////////////// - - /** - * Determines if the instance is equal to another - * - * @param Carbon $dt - * - * @return boolean - */ - public function eq(Carbon $dt) - { - return $this == $dt; - } - - /** - * Determines if the instance is not equal to another - * - * @param Carbon $dt - * - * @return boolean - */ - public function ne(Carbon $dt) - { - return !$this->eq($dt); - } - - /** - * Determines if the instance is greater (after) than another - * - * @param Carbon $dt - * - * @return boolean - */ - public function gt(Carbon $dt) - { - return $this > $dt; - } - - /** - * Determines if the instance is greater (after) than or equal to another - * - * @param Carbon $dt - * - * @return boolean - */ - public function gte(Carbon $dt) - { - return $this >= $dt; - } - - /** - * Determines if the instance is less (before) than another - * - * @param Carbon $dt - * - * @return boolean - */ - public function lt(Carbon $dt) - { - return $this < $dt; - } - - /** - * Determines if the instance is less (before) or equal to another - * - * @param Carbon $dt - * - * @return boolean - */ - public function lte(Carbon $dt) - { - return $this <= $dt; - } - - /** - * Determines if the instance is between two others - * - * @param Carbon $dt1 - * @param Carbon $dt2 - * @param boolean $equal Indicates if a > and < comparison should be used or <= or >= - * - * @return boolean - */ - public function between(Carbon $dt1, Carbon $dt2, $equal = true) - { - if ($dt1->gt($dt2)) { - $temp = $dt1; - $dt1 = $dt2; - $dt2 = $temp; - } - - if ($equal) { - return $this->gte($dt1) && $this->lte($dt2); - } else { - return $this->gt($dt1) && $this->lt($dt2); - } - } - - /** - * Get the minimum instance between a given instance (default now) and the current instance. - * - * @param Carbon $dt - * - * @return static - */ - public function min(Carbon $dt = null) - { - $dt = ($dt === null) ? static::now($this->tz) : $dt; - - return $this->lt($dt) ? $this : $dt; - } - - /** - * Get the maximum instance between a given instance (default now) and the current instance. - * - * @param Carbon $dt - * - * @return static - */ - public function max(Carbon $dt = null) - { - $dt = ($dt === null) ? static::now($this->tz) : $dt; - - return $this->gt($dt) ? $this : $dt; - } - - /** - * Determines if the instance is a weekday - * - * @return boolean - */ - public function isWeekday() - { - return ($this->dayOfWeek != self::SUNDAY && $this->dayOfWeek != self::SATURDAY); - } - - /** - * Determines if the instance is a weekend day - * - * @return boolean - */ - public function isWeekend() - { - return !$this->isWeekDay(); - } - - /** - * Determines if the instance is yesterday - * - * @return boolean - */ - public function isYesterday() - { - return $this->toDateString() === static::yesterday($this->tz)->toDateString(); - } - - /** - * Determines if the instance is today - * - * @return boolean - */ - public function isToday() - { - return $this->toDateString() === static::now($this->tz)->toDateString(); - } - - /** - * Determines if the instance is tomorrow - * - * @return boolean - */ - public function isTomorrow() - { - return $this->toDateString() === static::tomorrow($this->tz)->toDateString(); - } - - /** - * Determines if the instance is in the future, ie. greater (after) than now - * - * @return boolean - */ - public function isFuture() - { - return $this->gt(static::now($this->tz)); - } - - /** - * Determines if the instance is in the past, ie. less (before) than now - * - * @return boolean - */ - public function isPast() - { - return $this->lt(static::now($this->tz)); - } - - /** - * Determines if the instance is a leap year - * - * @return boolean - */ - public function isLeapYear() - { - return $this->format('L') == '1'; - } - - /** - * Checks if the passed in date is the same day as the instance current day. - * - * @param Carbon $dt - * @return boolean - */ - public function isSameDay(Carbon $dt) - { - return $this->toDateString() === $dt->toDateString(); - } - - /////////////////////////////////////////////////////////////////// - /////////////////// ADDITIONS AND SUBSTRACTIONS /////////////////// - /////////////////////////////////////////////////////////////////// - - /** - * Add years to the instance. Positive $value travel forward while - * negative $value travel into the past. - * - * @param integer $value - * - * @return static - */ - public function addYears($value) - { - return $this->modify((int) $value . ' year'); - } - - /** - * Add a year to the instance - * - * @return static - */ - public function addYear() - { - return $this->addYears(1); - } - - /** - * Remove a year from the instance - * - * @return static - */ - public function subYear() - { - return $this->addYears(-1); - } - - /** - * Remove years from the instance. - * - * @param integer $value - * - * @return static - */ - public function subYears($value) - { - return $this->addYears(-1 * $value); - } - - /** - * Add months to the instance. Positive $value travels forward while - * negative $value travels into the past. - * - * @param integer $value - * - * @return static - */ - public function addMonths($value) - { - return $this->modify((int) $value . ' month'); - } - - /** - * Add a month to the instance - * - * @return static - */ - public function addMonth() - { - return $this->addMonths(1); - } - - /** - * Remove a month from the instance - * - * @return static - */ - public function subMonth() - { - return $this->addMonths(-1); - } - - /** - * Remove months from the instance - * - * @param integer $value - * - * @return static - */ - public function subMonths($value) - { - return $this->addMonths(-1 * $value); - } - - /** - * Add days to the instance. Positive $value travels forward while - * negative $value travels into the past. - * - * @param integer $value - * - * @return static - */ - public function addDays($value) - { - return $this->modify((int) $value . ' day'); - } - - /** - * Add a day to the instance - * - * @return static - */ - public function addDay() - { - return $this->addDays(1); - } - - /** - * Remove a day from the instance - * - * @return static - */ - public function subDay() - { - return $this->addDays(-1); - } - - /** - * Remove days from the instance - * - * @param integer $value - * - * @return static - */ - public function subDays($value) - { - return $this->addDays(-1 * $value); - } - - /** - * Add weekdays to the instance. Positive $value travels forward while - * negative $value travels into the past. - * - * @param integer $value - * - * @return static - */ - public function addWeekdays($value) - { - return $this->modify((int) $value . ' weekday'); - } - - /** - * Add a weekday to the instance - * - * @return static - */ - public function addWeekday() - { - return $this->addWeekdays(1); - } - - /** - * Remove a weekday from the instance - * - * @return static - */ - public function subWeekday() - { - return $this->addWeekdays(-1); - } - - /** - * Remove weekdays from the instance - * - * @param integer $value - * - * @return static - */ - public function subWeekdays($value) - { - return $this->addWeekdays(-1 * $value); - } - - /** - * Add weeks to the instance. Positive $value travels forward while - * negative $value travels into the past. - * - * @param integer $value - * - * @return static - */ - public function addWeeks($value) - { - return $this->modify((int) $value . ' week'); - } - - /** - * Add a week to the instance - * - * @return static - */ - public function addWeek() - { - return $this->addWeeks(1); - } - - /** - * Remove a week from the instance - * - * @return static - */ - public function subWeek() - { - return $this->addWeeks(-1); - } - - /** - * Remove weeks to the instance - * - * @param integer $value - * - * @return static - */ - public function subWeeks($value) - { - return $this->addWeeks(-1 * $value); - } - - /** - * Add hours to the instance. Positive $value travels forward while - * negative $value travels into the past. - * - * @param integer $value - * - * @return static - */ - public function addHours($value) - { - return $this->modify((int) $value . ' hour'); - } - - /** - * Add an hour to the instance - * - * @return static - */ - public function addHour() - { - return $this->addHours(1); - } - - /** - * Remove an hour from the instance - * - * @return static - */ - public function subHour() - { - return $this->addHours(-1); - } - - /** - * Remove hours from the instance - * - * @param integer $value - * - * @return static - */ - public function subHours($value) - { - return $this->addHours(-1 * $value); - } - - /** - * Add minutes to the instance. Positive $value travels forward while - * negative $value travels into the past. - * - * @param integer $value - * - * @return static - */ - public function addMinutes($value) - { - return $this->modify((int) $value . ' minute'); - } - - /** - * Add a minute to the instance - * - * @return static - */ - public function addMinute() - { - return $this->addMinutes(1); - } - - /** - * Remove a minute from the instance - * - * @return static - */ - public function subMinute() - { - return $this->addMinutes(-1); - } - - /** - * Remove minutes from the instance - * - * @param integer $value - * - * @return static - */ - public function subMinutes($value) - { - return $this->addMinutes(-1 * $value); - } - - /** - * Add seconds to the instance. Positive $value travels forward while - * negative $value travels into the past. - * - * @param integer $value - * - * @return static - */ - public function addSeconds($value) - { - return $this->modify((int) $value . ' second'); - } - - /** - * Add a second to the instance - * - * @return static - */ - public function addSecond() - { - return $this->addSeconds(1); - } - - /** - * Remove a second from the instance - * - * @return static - */ - public function subSecond() - { - return $this->addSeconds(-1); - } - - /** - * Remove seconds from the instance - * - * @param integer $value - * - * @return static - */ - public function subSeconds($value) - { - return $this->addSeconds(-1 * $value); - } - - /////////////////////////////////////////////////////////////////// - /////////////////////////// DIFFERENCES /////////////////////////// - /////////////////////////////////////////////////////////////////// - - /** - * Get the difference in years - * - * @param Carbon $dt - * @param boolean $abs Get the absolute of the difference - * - * @return integer - */ - public function diffInYears(Carbon $dt = null, $abs = true) - { - $dt = ($dt === null) ? static::now($this->tz) : $dt; - - return (int) $this->diff($dt, $abs)->format('%r%y'); - } - - /** - * Get the difference in months - * - * @param Carbon $dt - * @param boolean $abs Get the absolute of the difference - * - * @return integer - */ - public function diffInMonths(Carbon $dt = null, $abs = true) - { - $dt = ($dt === null) ? static::now($this->tz) : $dt; - - return $this->diffInYears($dt, $abs) * self::MONTHS_PER_YEAR + $this->diff($dt, $abs)->format('%r%m'); - } - - /** - * Get the difference in weeks - * - * @param Carbon $dt - * @param boolean $abs Get the absolute of the difference - * - * @return integer - */ - public function diffInWeeks(Carbon $dt = null, $abs = true) - { - return (int) ($this->diffInDays($dt, $abs) / self::DAYS_PER_WEEK); - } - - /** - * Get the difference in days - * - * @param Carbon $dt - * @param boolean $abs Get the absolute of the difference - * - * @return integer - */ - public function diffInDays(Carbon $dt = null, $abs = true) - { - $dt = ($dt === null) ? static::now($this->tz) : $dt; - - return (int) $this->diff($dt, $abs)->format('%r%a'); - } - - /** - * Get the difference in days using a filter closure - * - * @param Closure $callback - * @param Carbon $dt - * @param boolean $abs Get the absolute of the difference - * - * @return int - */ - public function diffInDaysFiltered(Closure $callback, Carbon $dt = null, $abs = true) - { - $start = $this; - $end = ($dt === null) ? static::now($this->tz) : $dt; - $inverse = false; - - if ($end < $start) { - $start = $end; - $end = $this; - $inverse = true; - } - - $period = new DatePeriod($start, new DateInterval('P1D'), $end); - $days = array_filter(iterator_to_array($period), function (DateTime $date) use ($callback) { - return call_user_func($callback, Carbon::instance($date)); - }); - - $diff = count($days); - - return $inverse && !$abs ? -$diff : $diff; - } - - /** - * Get the difference in weekdays - * - * @param Carbon $dt - * @param boolean $abs Get the absolute of the difference - * - * @return int - */ - public function diffInWeekdays(Carbon $dt = null, $abs = true) - { - return $this->diffInDaysFiltered(function (Carbon $date) { - return $date->isWeekday(); - }, $dt, $abs); - } - - /** - * Get the difference in weekend days using a filter - * - * @param Carbon $dt - * @param boolean $abs Get the absolute of the difference - * - * @return int - */ - public function diffInWeekendDays(Carbon $dt = null, $abs = true) - { - return $this->diffInDaysFiltered(function (Carbon $date) { - return $date->isWeekend(); - }, $dt, $abs); - } - - /** - * Get the difference in hours - * - * @param Carbon $dt - * @param boolean $abs Get the absolute of the difference - * - * @return integer - */ - public function diffInHours(Carbon $dt = null, $abs = true) - { - return (int) ($this->diffInSeconds($dt, $abs) / self::SECONDS_PER_MINUTE / self::MINUTES_PER_HOUR); - } - - /** - * Get the difference in minutes - * - * @param Carbon $dt - * @param boolean $abs Get the absolute of the difference - * - * @return integer - */ - public function diffInMinutes(Carbon $dt = null, $abs = true) - { - return (int) ($this->diffInSeconds($dt, $abs) / self::SECONDS_PER_MINUTE); - } - - /** - * Get the difference in seconds - * - * @param Carbon $dt - * @param boolean $abs Get the absolute of the difference - * - * @return integer - */ - public function diffInSeconds(Carbon $dt = null, $abs = true) - { - $value = (($dt === null) ? time() : $dt->getTimestamp()) - $this->getTimestamp(); - - return $abs ? abs($value) : $value; - } - - /** - * Get the difference in a human readable format. - * - * When comparing a value in the past to default now: - * 1 hour ago - * 5 months ago - * - * When comparing a value in the future to default now: - * 1 hour from now - * 5 months from now - * - * When comparing a value in the past to another value: - * 1 hour before - * 5 months before - * - * When comparing a value in the future to another value: - * 1 hour after - * 5 months after - * - * @param Carbon $other - * - * @return string - */ - public function diffForHumans(Carbon $other = null) - { - $isNow = $other === null; - - if ($isNow) { - $other = static::now($this->tz); - } - - $isFuture = $this->gt($other); - - $delta = $other->diffInSeconds($this); - - // a little weeks per month, 365 days per year... good enough!! - $divs = array( - 'second' => self::SECONDS_PER_MINUTE, - 'minute' => self::MINUTES_PER_HOUR, - 'hour' => self::HOURS_PER_DAY, - 'day' => self::DAYS_PER_WEEK, - 'week' => 30 / self::DAYS_PER_WEEK, - 'month' => self::MONTHS_PER_YEAR - ); - - $unit = 'year'; - - foreach ($divs as $divUnit => $divValue) { - if ($delta < $divValue) { - $unit = $divUnit; - break; - } - - $delta = $delta / $divValue; - } - - $delta = (int) $delta; - - if ($delta == 0) { - $delta = 1; - } - - $txt = $delta . ' ' . $unit; - $txt .= $delta == 1 ? '' : 's'; - - if ($isNow) { - if ($isFuture) { - return $txt . ' from now'; - } - - return $txt . ' ago'; - } - - if ($isFuture) { - return $txt . ' after'; - } - - return $txt . ' before'; - } - - /////////////////////////////////////////////////////////////////// - //////////////////////////// MODIFIERS //////////////////////////// - /////////////////////////////////////////////////////////////////// - - /** - * Resets the time to 00:00:00 - * - * @return static - */ - public function startOfDay() - { - return $this->hour(0)->minute(0)->second(0); - } - - /** - * Resets the time to 23:59:59 - * - * @return static - */ - public function endOfDay() - { - return $this->hour(23)->minute(59)->second(59); - } - - /** - * Resets the date to the first day of the month and the time to 00:00:00 - * - * @return static - */ - public function startOfMonth() - { - return $this->startOfDay()->day(1); - } - - /** - * Resets the date to end of the month and time to 23:59:59 - * - * @return static - */ - public function endOfMonth() - { - return $this->day($this->daysInMonth)->endOfDay(); - } - - /** - * Resets the date to the first day of the year and the time to 00:00:00 - * - * @return static - */ - public function startOfYear() - { - return $this->month(1)->startOfMonth(); - } - - /** - * Resets the date to end of the year and time to 23:59:59 - * - * @return static - */ - public function endOfYear() - { - return $this->month(self::MONTHS_PER_YEAR)->endOfMonth(); - } - - /** - * Resets the date to the first day of the decade and the time to 00:00:00 - * - * @return static - */ - public function startOfDecade() - { - return $this->startOfYear()->year($this->year - $this->year % self::YEARS_PER_DECADE); - } - - /** - * Resets the date to end of the decade and time to 23:59:59 - * - * @return static - */ - public function endOfDecade() - { - return $this->endOfYear()->year($this->year - $this->year % self::YEARS_PER_DECADE + self::YEARS_PER_DECADE - 1); - } - - /** - * Resets the date to the first day of the century and the time to 00:00:00 - * - * @return static - */ - public function startOfCentury() - { - return $this->startOfYear()->year($this->year - $this->year % self::YEARS_PER_CENTURY); - } - - /** - * Resets the date to end of the century and time to 23:59:59 - * - * @return static - */ - public function endOfCentury() - { - return $this->endOfYear()->year($this->year - $this->year % self::YEARS_PER_CENTURY + self::YEARS_PER_CENTURY - 1); - } - - /** - * Resets the date to the first day of the ISO-8601 week (Monday) and the time to 00:00:00 - * - * @return static - */ - public function startOfWeek() - { - if ($this->dayOfWeek != self::MONDAY) $this->previous(self::MONDAY); - return $this->startOfDay(); - } - - /** - * Resets the date to end of the ISO-8601 week (Sunday) and time to 23:59:59 - * - * @return static - */ - public function endOfWeek() - { - if ($this->dayOfWeek != self::SUNDAY) $this->next(self::SUNDAY); - return $this->endOfDay(); - } - - /** - * Modify to the next occurrence of a given day of the week. - * If no dayOfWeek is provided, modify to the next occurrence - * of the current day of the week. Use the supplied consts - * to indicate the desired dayOfWeek, ex. static::MONDAY. - * - * @param int $dayOfWeek - * - * @return mixed - */ - public function next($dayOfWeek = null) - { - if ($dayOfWeek === null) { - $dayOfWeek = $this->dayOfWeek; - } - - return $this->startOfDay()->modify('next ' . self::$days[$dayOfWeek]); - } - - /** - * Modify to the previous occurrence of a given day of the week. - * If no dayOfWeek is provided, modify to the previous occurrence - * of the current day of the week. Use the supplied consts - * to indicate the desired dayOfWeek, ex. static::MONDAY. - * - * @param int $dayOfWeek - * - * @return mixed - */ - public function previous($dayOfWeek = null) - { - if ($dayOfWeek === null) { - $dayOfWeek = $this->dayOfWeek; - } - - return $this->startOfDay()->modify('last ' . self::$days[$dayOfWeek]); - } - - /** - * Modify to the first occurrence of a given day of the week - * in the current month. If no dayOfWeek is provided, modify to the - * first day of the current month. Use the supplied consts - * to indicate the desired dayOfWeek, ex. static::MONDAY. - * - * @param int $dayOfWeek - * - * @return mixed - */ - public function firstOfMonth($dayOfWeek = null) - { - $this->startOfDay(); - - if ($dayOfWeek === null) { - return $this->day(1); - } - - return $this->modify('first ' . self::$days[$dayOfWeek] . ' of ' . $this->format('F') . ' ' . $this->year); - } - - /** - * Modify to the last occurrence of a given day of the week - * in the current month. If no dayOfWeek is provided, modify to the - * last day of the current month. Use the supplied consts - * to indicate the desired dayOfWeek, ex. static::MONDAY. - * - * @param int $dayOfWeek - * - * @return mixed - */ - public function lastOfMonth($dayOfWeek = null) - { - $this->startOfDay(); - - if ($dayOfWeek === null) { - return $this->day($this->daysInMonth); - } - - return $this->modify('last ' . self::$days[$dayOfWeek] . ' of ' . $this->format('F') . ' ' . $this->year); - } - - /** - * Modify to the given occurrence of a given day of the week - * in the current month. If the calculated occurrence is outside the scope - * of the current month, then return false and no modifications are made. - * Use the supplied consts to indicate the desired dayOfWeek, ex. static::MONDAY. - * - * @param int $nth - * @param int $dayOfWeek - * - * @return mixed - */ - public function nthOfMonth($nth, $dayOfWeek) - { - $dt = $this->copy()->firstOfMonth(); - $check = $dt->format('Y-m'); - $dt->modify('+' . $nth . ' ' . self::$days[$dayOfWeek]); - - return ($dt->format('Y-m') === $check) ? $this->modify($dt) : false; - } - - /** - * Modify to the first occurrence of a given day of the week - * in the current quarter. If no dayOfWeek is provided, modify to the - * first day of the current quarter. Use the supplied consts - * to indicate the desired dayOfWeek, ex. static::MONDAY. - * - * @param int $dayOfWeek - * - * @return mixed - */ - public function firstOfQuarter($dayOfWeek = null) - { - return $this->day(1)->month($this->quarter * 3 - 2)->firstOfMonth($dayOfWeek); - } - - /** - * Modify to the last occurrence of a given day of the week - * in the current quarter. If no dayOfWeek is provided, modify to the - * last day of the current quarter. Use the supplied consts - * to indicate the desired dayOfWeek, ex. static::MONDAY. - * - * @param int $dayOfWeek - * - * @return mixed - */ - public function lastOfQuarter($dayOfWeek = null) - { - return $this->day(1)->month($this->quarter * 3)->lastOfMonth($dayOfWeek); - } - - /** - * Modify to the given occurrence of a given day of the week - * in the current quarter. If the calculated occurrence is outside the scope - * of the current quarter, then return false and no modifications are made. - * Use the supplied consts to indicate the desired dayOfWeek, ex. static::MONDAY. - * - * @param int $nth - * @param int $dayOfWeek - * - * @return mixed - */ - public function nthOfQuarter($nth, $dayOfWeek) - { - $dt = $this->copy()->day(1)->month($this->quarter * 3); - $last_month = $dt->month; - $year = $dt->year; - $dt->firstOfQuarter()->modify('+' . $nth . ' ' . self::$days[$dayOfWeek]); - - return ($last_month < $dt->month || $year !== $dt->year) ? false : $this->modify($dt); - } - - /** - * Modify to the first occurrence of a given day of the week - * in the current year. If no dayOfWeek is provided, modify to the - * first day of the current year. Use the supplied consts - * to indicate the desired dayOfWeek, ex. static::MONDAY. - * - * @param int $dayOfWeek - * - * @return mixed - */ - public function firstOfYear($dayOfWeek = null) - { - return $this->month(1)->firstOfMonth($dayOfWeek); - } - - /** - * Modify to the last occurrence of a given day of the week - * in the current year. If no dayOfWeek is provided, modify to the - * last day of the current year. Use the supplied consts - * to indicate the desired dayOfWeek, ex. static::MONDAY. - * - * @param int $dayOfWeek - * - * @return mixed - */ - public function lastOfYear($dayOfWeek = null) - { - return $this->month(self::MONTHS_PER_YEAR)->lastOfMonth($dayOfWeek); - } - - /** - * Modify to the given occurrence of a given day of the week - * in the current year. If the calculated occurrence is outside the scope - * of the current year, then return false and no modifications are made. - * Use the supplied consts to indicate the desired dayOfWeek, ex. static::MONDAY. - * - * @param int $nth - * @param int $dayOfWeek - * - * @return mixed - */ - public function nthOfYear($nth, $dayOfWeek) - { - $dt = $this->copy()->firstOfYear()->modify('+' . $nth . ' ' . self::$days[$dayOfWeek]); - - return $this->year == $dt->year ? $this->modify($dt) : false; - } - - /** - * Modify the current instance to the average of a given instance (default now) and the current instance. - * - * @param Carbon $dt - * - * @return static - */ - public function average(Carbon $dt = null) - { - $dt = ($dt === null) ? static::now($this->tz) : $dt; - - return $this->addSeconds((int) ($this->diffInSeconds($dt, false) / 2)); - } - - /** - * Check if its the birthday. Compares the date/month values of the two dates. - * @param Carbon $dt - * @return boolean - */ - public function isBirthday(Carbon $dt) - { - return $this->month === $dt->month && $this->day === $dt->day; - } -} diff --git a/local/public/wp-config.php b/local/public/wp-config.php index ae947c5e..17596db0 100644 --- a/local/public/wp-config.php +++ b/local/public/wp-config.php @@ -31,7 +31,10 @@ // Keep the wp-contents outside of WP core directory. define( 'WP_CONTENT_DIR', __DIR__ . '/wp-content' ); -define( 'ABSPATH', __DIR__ . '/wp/' ); +/** Absolute path to the WordPress directory. */ +if ( ! defined( 'ABSPATH' ) ) { + define( 'ABSPATH', __DIR__ . '/wp/' ); +} // For mercator. define( 'SUNRISE', true ); diff --git a/tests/tests/test-class-date-interval.php b/tests/tests/test-class-date-interval.php index e637b9e7..8df354e0 100644 --- a/tests/tests/test-class-date-interval.php +++ b/tests/tests/test-class-date-interval.php @@ -48,4 +48,52 @@ public function test_get_predefined_intervals() { $this->assertArrayHasKey( 'end', $interval ); } } + + /** + * Test generate_date_intervals + * + * @return void + * @throws \Exception + */ + public function test_generate_date_intervals() { + $timezone = new \DateTimeZone( 'UTC' ); + $date = new \DateTimeImmutable( '2024-07-18', $timezone ); + $intervals = $this->date_interval->generate_date_intervals( $date ); + + $this->assertSame( '2024-07-18T00:00:00+00:00', $intervals['today']['start']->format( DATE_ATOM ) ); + $this->assertSame( '2024-07-18T23:59:59+00:00', $intervals['today']['end']->format( DATE_ATOM ) ); + + $this->assertSame( '2024-07-17T00:00:00+00:00', $intervals['yesterday']['start']->format( DATE_ATOM ) ); + $this->assertSame( '2024-07-17T23:59:59+00:00', $intervals['yesterday']['end']->format( DATE_ATOM ) ); + + $this->assertSame( '2024-07-11T00:00:00+00:00', $intervals['last-7-days']['start']->format( DATE_ATOM ) ); + $this->assertSame( '2024-07-18T00:00:00+00:00', $intervals['last-7-days']['end']->format( DATE_ATOM ) ); + + $this->assertSame( '2024-07-04T00:00:00+00:00', $intervals['last-14-days']['start']->format( DATE_ATOM ) ); + $this->assertSame( '2024-07-18T00:00:00+00:00', $intervals['last-14-days']['end']->format( DATE_ATOM ) ); + + $this->assertSame( '2024-06-18T00:00:00+00:00', $intervals['last-30-days']['start']->format( DATE_ATOM ) ); + $this->assertSame( '2024-07-18T00:00:00+00:00', $intervals['last-30-days']['end']->format( DATE_ATOM ) ); + + $this->assertSame( '2024-07-01T00:00:00+00:00', $intervals['this-month']['start']->format( DATE_ATOM ) ); + $this->assertSame( '2024-07-31T23:59:59+00:00', $intervals['this-month']['end']->format( DATE_ATOM ) ); + + $this->assertSame( '2024-06-01T00:00:00+00:00', $intervals['last-month']['start']->format( DATE_ATOM ) ); + $this->assertSame( '2024-06-30T23:59:59+00:00', $intervals['last-month']['end']->format( DATE_ATOM ) ); + + $this->assertSame( '2024-04-18T00:00:00+00:00', $intervals['last-3-months']['start']->format( DATE_ATOM ) ); + $this->assertSame( '2024-07-18T00:00:00+00:00', $intervals['last-3-months']['end']->format( DATE_ATOM ) ); + + $this->assertSame( '2024-01-18T00:00:00+00:00', $intervals['last-6-months']['start']->format( DATE_ATOM ) ); + $this->assertSame( '2024-07-18T00:00:00+00:00', $intervals['last-6-months']['end']->format( DATE_ATOM ) ); + + $this->assertSame( '2023-07-18T00:00:00+00:00', $intervals['last-12-months']['start']->format( DATE_ATOM ) ); + $this->assertSame( '2024-07-18T00:00:00+00:00', $intervals['last-12-months']['end']->format( DATE_ATOM ) ); + + $this->assertSame( '2024-01-01T00:00:00+00:00', $intervals['this-year']['start']->format( DATE_ATOM ) ); + $this->assertSame( '2024-12-31T23:59:59+00:00', $intervals['this-year']['end']->format( DATE_ATOM ) ); + + $this->assertSame( '2023-01-01T00:00:00+00:00', $intervals['last-year']['start']->format( DATE_ATOM ) ); + $this->assertSame( '2023-12-31T23:59:59+00:00', $intervals['last-year']['end']->format( DATE_ATOM ) ); + } }