/**
  * Check whether the result for the given sets is true based on the specified closure filter.
  * By default true will be returned if any object set has the result true, if <var>$all</var> is set to true all
  * object sets must have a result of true. False is returned otherwise.
  *
  * The number of objects in all sets must be equal, some sets may equal one.
  * If the number of objects in all sets equals, all objects will be compared to the object in the other set at the
  * same set index. If a set contains one object, this one object will be compared to the relevant objects of the
  * other sets.
  *
  * A non-array object may be given which is then converted into an array.
  *
  * The closure filter one argument, which is an array of all the relevant DateTime objects for that iteration. The
  * number of objects in this array equals the number of available sets. The filter must return true if the result
  * is correct, or false if not. Null may be returned on failure.
  *
  * @param Array $sets [optional] An array containing all sets as arrays, with values accepted by
  *     DateTimeArrayUtils::parse().
  * @param Closure $callback The filter to run for each object set.
  * @param bool $all [optional] True to require all object sets to return true, false if not.
  * @param mixed|null $default [optional] The default value returned on failure.
  *
  * @return bool|mixed True if any of the iterations gives a result of true, if <var>$all</var> is set to true all
  *     iterations must give a result of true to return true, false will be returned otherwise. The default value
  *     will be returned on failure.
  */
 public static function compareSets($sets, Closure $callback, $all = true, $default = null)
 {
     // Make sure the sets parameter is an array
     if (!is_array($sets)) {
         return $default;
     }
     // Make sure all sets are arrays
     foreach ($sets as &$value) {
         if (!is_array($value)) {
             $value = array($value);
         }
     }
     // Unset the value reference to prevent accidental modifications
     unset($value);
     // Make sure the closure is valid
     if (!Utils::isValidClosure($callback)) {
         return $default;
     }
     // Count the values of all sets
     $setCounts = array();
     foreach ($sets as $value) {
         $setCounts[] = count($value);
     }
     $countMax = max($setCounts);
     $setCount = count($sets);
     // Make sure all counts equal the maximum count or one
     foreach ($setCounts as $count) {
         if ($count != 1 && $count != $countMax) {
             return $default;
         }
     }
     // Define the variables for all set values
     $setValues = array_fill(0, $setCount, null);
     // Predefine and parse sets with a single element for better performance
     for ($valueIndex = 0; $valueIndex < $setCount; $valueIndex++) {
         if ($setCounts[$valueIndex] == 1) {
             if (($setValues[$valueIndex] = DateTime::parse($sets[$valueIndex], null)) === null) {
                 return $default;
             }
         }
     }
     // Loop through the objects
     for ($valueIndex = 0; $valueIndex < $countMax; $valueIndex++) {
         // Update all values for the sets that have more than one item
         foreach ($sets as $setIndex => $value) {
             if ($setCounts[$setIndex] > 1) {
                 $setValues[$setIndex] = $value[$valueIndex];
             }
         }
         // Check whether any of the set values is an array
         $isArray = false;
         foreach ($setValues as $value) {
             if (is_array($value)) {
                 $isArray = true;
                 break;
             }
         }
         // Handle recursive arrays
         if ($isArray) {
             // Get the result from the recursive array
             $result = static::compareSets($setValues, $callback, $all, null);
             // Return the default value if the result is invalid
             if ($result === null) {
                 return $default;
             }
         } else {
             // Parse all set values that have sets with more than one item, return the default value on failure
             foreach ($setValues as $setIndex2 => &$setValue2) {
                 if ($setCounts[$setIndex2] > 1) {
                     if (($setValue2 = DateTime::parse($setValue2, null)) === null) {
                         return $default;
                     }
                 }
             }
             // Call the closure to get the result
             $result = call_user_func($callback, $setValues);
             // Make sure the value is boolean, or return the default value
             if (!is_bool($result)) {
                 return $default;
             }
         }
         // Return false if the result is false while everything must be true
         if (!$result && $all) {
             return false;
         }
         // Return true if the result is true while anything must be true
         if ($result && !$all) {
             return true;
         }
     }
     // Return the result
     return (bool) $all;
 }
 /**
  * Returns all transitions for the timezone in the specified time frame.
  *
  * @param int|DateTime|PHPDateTime|string|null $timestampBegin [optional] The end timestamp, a DateTime or
  *     PHPDateTime instance, the date and time as a string or null.
  *
  * @param null $timestampEnd
  *
  * @return Array|null Returns a numerically indexed array containing associative arrays with all transitions, or
  *     null on failure.
  *
  * @throws Exception Throws an exception on failure.
  *
  * @link http://php.net/manual/en/datetimezone.gettransitions.php
  */
 public function getTransitions($timestampBegin = null, $timestampEnd = null)
 {
     // Try to parse the timestamps for the begin and end parameter
     if ($timestampBegin !== null && !is_int($timestampBegin)) {
         // Parse the timestamp, throw an exception on failure
         if (($timestampBegin = DateTime::parse($timestampBegin)) === null) {
             throw new Exception('Invalid begin timestamp');
         }
         // Gather the timestamp
         $timestampBegin = $timestampBegin->getTimestamp();
     }
     if ($timestampEnd !== null && !is_int($timestampEnd)) {
         // Parse the timestamp, throw an exception on failure
         if (($timestampEnd = DateTime::parse($timestampEnd)) === null) {
             throw new Exception('Invalid end timestamp');
         }
         // Gather the timestamp
         $timestampEnd = $timestampEnd->getTimestamp();
     }
     // Get and return the transitions, return null on failure
     return ($transitions = parent::getTransitions($timestampBegin, $timestampEnd)) !== false ? $transitions : null;
 }
 /**
  * Set a cookie.
  *
  * @param string $key Cookie key.
  * @param mixed $value Cookie value.
  * @param string|DatePeriod $duration Duration or period.
  * @param string|null $path [optional] Cookie path.
  * @param string|null $domain [optional] Cookie domain.
  */
 public static function setCookie($key, $value, $duration, $path = null, $domain = null)
 {
     // Determine the expiration date time
     $expirationDateTime = DateTime::parse($duration);
     // Parse the cookie path and domain
     if ($path === null) {
         $path = static::$path;
     }
     if ($domain === null) {
         $domain = static::$domain;
     }
     // Set the cookie
     setcookie(static::getFullCookieKey($key), $value, $expirationDateTime->getTimestamp(), $path, $domain);
 }
 /**
  * Parse a date and time with an optional time zone. A new instance will be created if required.
  *
  * If the $dateTime parameter is a DateTime zone instance, the instance will be returned and the $timezone
  * parameter is ignored. If the $dateTime parameter is anything other than a DateTime zone the date, time and the
  * time zone is parsed through the constructor.
  *
  * This method allows better fluent syntax because it makes method chaining possible.
  *
  * @param DateTime|PHPDateTime|string|null $dateTime [optional] A DateTime or PHPDateTime instance, the time as a string, or
  *     null to use the now() time.
  * @param DateTimeZone|PHPDateTimeZone|string|DateTime|PHPDateTime|null $timezone [optional] The time zone the
  *     specified time is in, or null to use the default time zone if the $time param isn't a DateTime instance. A
  *     DateTime or PHPDateTime instance to use it's timezone.
  * @param mixed|null $default [optional] The default value returned on failure.
  *
  * @return DateTime|mixed The DateTime instance, or the default value on failure.
  */
 public static function parse($dateTime = null, $timezone = null, $default = null)
 {
     return ($result = DateTime::parse($dateTime, $timezone)) !== null ? $result : $default;
 }