Skip to content

Instantly share code, notes, and snippets.

@timvisee
Created May 3, 2015 12:52
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save timvisee/c27356fc1acad88dbbba to your computer and use it in GitHub Desktop.
Save timvisee/c27356fc1acad88dbbba to your computer and use it in GitHub Desktop.
<?php
namespace carbon\core\datetime\interval;
use carbon\core\datetime\DateTime;
use DateInterval as PHPDateInterval;
use DomainException;
use Exception;
use InvalidArgumentException;
// Prevent direct requests to this set_file due to security reasons
defined('CARBON_CORE_INIT') or die('Access denied!');
/**
* Class DateInterval
*
* @package carbon\core\datetime
*
* @TODO Update these properties below!
* @TODO Rename this to 'daysOfWeek'?
*
* property-read int $daysExcludeWeeks Total days remaining in the final week of the current instance (days % 7).
*/
class DateInterval extends PHPDateInterval {
// TODO: Should we create a DateDuration class which is similar to this class?
// TODO: Throw better exceptions!
// TODO: Rename sub... methods to subtract...?
/**
* The date interval specification prefix designator.
*
* @const string The period prefix.
*/
const PERIOD_PREFIX = 'P';
/**
* The date interval specification year designator.
*
* @const string The year prefix.
*/
const PERIOD_YEARS = 'Y';
/**
* The date interval specification month designator.
*
* @const string The month prefix.
*/
const PERIOD_MONTHS = 'M';
/**
* The date interval specification day designator.
*
* @const string The day prefix.
*/
const PERIOD_DAYS = 'D';
/**
* The date interval specification time designator.
*
* @const string The time prefix.
*/
const PERIOD_TIME_PREFIX = 'T';
/**
* The date interval specification hour designator.
*
* @const string The hour prefix.
*/
const PERIOD_HOURS = 'H';
/**
* The date interval specification minute designator.
*
* @const string The minute prefix.
*/
const PERIOD_MINUTES = 'M';
/**
* The date interval specification second designator.
*
* @const string The second prefix.
*/
const PERIOD_SECONDS = 'S';
/**
* Constructor.
*
* @param string|PHPDateInterval|PHPDateInterval|null $dateIntervalSpec [optional] A date interval specification, a
* DateInterval or PHPDateInterval instance, or null to use a zero specification.
* @param bool $inverted [optional] Defines whether the date interval specification is inverted or not, this
* parameter is ignored if a DateInterval or PHPDateInterval instance is given for the $dateIntervalSpec
* parameter.
*
* @throws Exception Throws an exception on failure.
*/
public function __construct($dateIntervalSpec, $inverted = false) {
// Parse string specifications
if(is_string($dateIntervalSpec)) {
// Make sure the specification is valid
if(!DateIntervalSpecUtils::isValid($dateIntervalSpec))
throw new \DomainException('Invalid date interval specification (\'' . $dateIntervalSpec .
'\' was given)');
// Set the specification
$spec = $dateIntervalSpec;
} else if($dateIntervalSpec instanceof self) { // Parse DateInterval instances
// Set whether this date interval is inverted and create a specification string
$inverted = $dateIntervalSpec->invert;
$spec = $dateIntervalSpec->toSpecString();
} else if($dateIntervalSpec instanceof parent) { // Parse PHPDateInterval instances
// Set whether this date interval is inverted and create a specification string
$inverted = $dateIntervalSpec->invert;
$spec =
DateIntervalSpecUtils::create($dateIntervalSpec->y, $dateIntervalSpec->m, null, $dateIntervalSpec->d,
$dateIntervalSpec->h, $dateIntervalSpec->i, $dateIntervalSpec->s);
} else if($dateIntervalSpec === null) // Use a zero specification if the parameter is null
// Create a zero specification
$spec = DateIntervalFactory::zero();
// No valid date interval specification was given, throw an exception
else
throw new \DomainException('Invalid date interval specification (\'' . $dateIntervalSpec . '\' was given)');
// Construct the parent object, and set whether the date interval is inverted
parent::__construct($spec);
$this->setInverted($inverted);
}
/**
* Parse a date interval. A new instance may be created.
*
* This method allows better fluent syntax because it makes method chaining possible.
*
* @param PHPDateInterval|PHPDateInterval|string|null $dateInterval [optional] A DateInterval or PHPDateInterval
* instance, a date interval specification, or null to use a zero specification.
*
* @return static A DateInterval instance, or null on failure.
*/
// TODO: Don't use exception catching? Is it bad?
// TODO: Accept relative times, such as '-2 days'!
public static function parse($dateInterval) {
// Return the object if it's already a DateInterval instance
if($dateInterval instanceof self)
return $dateInterval;
// Make sure the spec is valid if th date interval parameter is a string
if(is_string($dateInterval))
if(!DateIntervalSpecUtils::isValid($dateInterval))
return null;
// Parse and return the date and time, return the default value on failure
try {
// TODO: This object can't be constructed (currently) using this single parameter, use better parsing!
return new static($dateInterval);
} catch(InvalidArgumentException $ex) {
return null;
}
}
/**
* Create a DateInterval instance from a DateInterval one. Can not instance
* DateInterval objects created from DateTime::diff() as you can't externally
* set the $days field.
*
* @param PHPDateInterval|PHPDateInterval|string $dateInterval
*
* @throws InvalidArgumentException
*
* @return static A new DateTime instance.
*/
// TODO: Update docs!
// TODO: Parse the date interval parameter?
// TODO: Support null!
public static function instance($dateInterval) {
// TODO: Is this necessary?
if(DateIntervalUtils::isCreatedFromDiff($dateInterval))
throw new InvalidArgumentException("Can not instance a DateInterval object created from DateTime::diff().");
// Parse DateInterval instances, create a new instance
if($dateInterval instanceof self)
return new static($dateInterval->toSpecString(), $dateInterval->isInverted());
// Try to parse and instantiate other specifications and return the result
return static::parse($dateInterval);
}
/**
* Create a copy of this instance.
*
* @return PHPDateInterval The DateInterval instance copy.
*/
public function copy() {
return static::instance($this);
}
/**
* Clone this instance.
*
* @return PHPDateInterval A DateInterval instance clone.
*/
public function __clone() {
return $this->copy();
}
/**
* Add the given number of years, months, weeks, days, hours, minutes and seconds to the date interval.
* The resulting values may not be a negative number, or an exception will be thrown.
*
* @param int|null $years The number of years to add to the interval. Null to ignore this value.
* @param int|null $months The number of months to add to the interval. Null to ignore this value.
* @param int|null $weeks The number of weeks to add to the interval, this is converted into and added to the
* number of days. Null to ignore this value.
* @param int|null $days The number of days to add to the interval. Null to ignore this value.
* @param int|null $hours The number of hours to add to the interval. Null to ignore this value.
* @param int|null $minutes The number of minutes to add to the interval. Null to ignore this value.
* @param int|null $seconds The number of seconds to add to the interval. Null to ignore this value.
*
* @return static The DateTime instance for method chaining.
*
* @throws DomainException|Exception Throws an exception on failure.
*/
public function addDateTime($years = null, $months = null, $weeks = null, $days = null, $hours = null,
$minutes = null, $seconds = null) {
// Add the date and time part
$this->addDate($years, $months, $weeks, $days);
$this->addTime($hours, $minutes, $seconds);
// Return this instance
return $this;
}
/**
* Subtract the given number of years, months, weeks, days, hours, minutes and seconds to the date interval.
* The resulting values may not be a negative number, or an exception will be thrown.
*
* @param int|null $years The number of years to subtract to the interval. Null to ignore this value.
* @param int|null $months The number of months to subtract to the interval. Null to ignore this value.
* @param int|null $weeks The number of weeks to subtract to the interval, this is converted into and added to the
* number of days. Null to ignore this value.
* @param int|null $days The number of days to subtract to the interval. Null to ignore this value.
* @param int|null $hours The number of hours to subtract to the interval. Null to ignore this value.
* @param int|null $minutes The number of minutes to subtract to the interval. Null to ignore this value.
* @param int|null $seconds The number of seconds to subtract to the interval. Null to ignore this value.
*
* @return static The DateTime instance for method chaining.
*
* @throws DomainException|Exception Throws an exception on failure.
*/
public function subDateTime($years = null, $months = null, $weeks = null, $days = null, $hours = null,
$minutes = null, $seconds = null) {
// Subtract the date and time part
$this->subDate($years, $months, $weeks, $days);
$this->subTime($hours, $minutes, $seconds);
// Return this instance
return $this;
}
/**
* Set the time part of the interval. This changes the specified hours, minutes and seconds.
*
* @param int|null $years The number of years of the interval. Null to ignore this value.
* @param int|null $months The number of months of the interval. Null to ignore this value.
* @param int|null $weeks The number of weeks of the interval, this is converted into and added to the number of
* days. Null to ignore this value.
* @param int|null $days The number of days of the interval. Null to ignore this value.
* @param int|null $hours The number of hours of the interval. Null to ignore this value.
* @param int|null $minutes The number of minutes of the interval. Null to ignore this value.
* @param int|null $seconds The number of seconds of the interval. Null to ignore this value.
*
* @return static This DateInterval instance for method chaining.
*/
public function setDateTime($years = null, $months = null, $weeks = null, $days = null, $hours = null,
$minutes = null, $seconds = null) {
// Set the date and time part
$this->setDate($years, $months, $weeks, $days);
$this->setTime($hours, $minutes, $seconds);
// Return this instance
return $this;
}
/**
* Add the given number of years, months, weeks and days to the date interval.
* The resulting values may not be a negative number, or an exception will be thrown.
*
* @param int|null $years The number of years to add to the interval. Null to ignore this value.
* @param int|null $months The number of months to add to the interval. Null to ignore this value.
* @param int|null $weeks The number of weeks to add to the interval, this is converted into and added to the
* number of days. Null to ignore this value.
* @param int|null $days The number of days to add to the interval. Null to ignore this value.
*
* @return static The DateTime instance for method chaining.
*
* @throws DomainException|Exception Throws an exception on failure.
*/
public function addDate($years = null, $months = null, $weeks = null, $days = null) {
// Add the number of years and months if set
if(!empty($years))
$this->addYears($years);
if(!empty($months))
$this->addMonths($months);
// Add the number of weeks and days
$this->addWeeksAndDays($weeks, $days);
// Return this instance for method chaining
return $this;
}
/**
* Subtract the given number of years, months, weeks and days to the date interval.
* The resulting values may not be a negative number, or an exception will be thrown.
*
* @param int|null $years The number of years to subtract of the interval. Null to ignore this value.
* @param int|null $months The number of months to subtract of the interval. Null to ignore this value.
* @param int|null $weeks The number of weeks to subtract of the interval, this is converted into and added to the
* number of days. Null to ignore this value.
* @param int|null $days The number of days to subtract of the interval. Null to ignore this value.
*
* @return static The DateTime instance for method chaining.
*
* @throws DomainException|Exception Throws an exception on failure.
*/
public function subDate($years = null, $months = null, $weeks = null, $days = null) {
// Subtract the number of years and months if set
if(!empty($years))
$this->subYears($years);
if(!empty($months))
$this->subMonths($months);
// Subtract the number of weeks and days
$this->subWeeksAndDays($weeks, $days);
// Return this instance for method chaining
return $this;
}
/**
* Set the date part of the interval. This changes the specified years, months and days.
*
* @param int|null $years The number of years of the interval. Null to ignore this value.
* @param int|null $months The number of months of the interval. Null to ignore this value.
* @param int|null $weeks The number of weeks of the interval, this is converted into and added to the number of
* days. Null to ignore this value.
* @param int|null $days The number of days of the interval. Null to ignore this value.
*
* @return static This DateInterval instance for method chaining.
*/
public function setDate($years = null, $months = null, $weeks = null, $days = null) {
// Set the years and months if set
if(!empty($years))
$this->setYears($years);
if(!empty($months))
$this->setMonths($months);
// Set the days
$this->setWeeksAndDays($weeks, $days);
// Return this instance
return $this;
}
/**
* Get the number of years.
*
* @return int Number of years.
*/
public function getYears() {
return $this->y;
}
/**
* Add the given number of years to the date interval.
* The resulting number of years may not be a negative number, or an exception will be thrown.
*
* @param int $years [optional] The number of years to add.
*
* @return static The DateTime instance for method chaining.
*
* @throws DomainException|Exception Throws an exception on failure.
*/
public function addYears($years = 1) {
// Make sure the years parameter is an integer
if(!is_int($years))
throw new DomainException('Invalid value for years, must be an integer (\'' . $years . '\' was given)');
// Calculate the new number of years
$years = $this->getYears() + intval($years);
// Make sure the number isn't negative
if($years < 0)
throw new Exception('The resulting number of years may not be negative (' . $years . ' is negative)');
// Set the number of years
$this->setYears($years);
// Return this instance for method chaining
return $this;
}
/**
* Add one, or the given number of years to the date interval.
* The resulting number of years may not be a negative number, or an exception will be thrown.
*
* @param int $years [optional] The number of years to add.
*
* @return static The DateTime instance for method chaining.
*
* @throws DomainException|Exception Throws an exception on failure.
*/
public function addYear($years = 1) {
return $this->addYears($years);
}
/**
* Subtract the given number of years to the date interval.
* The resulting number of years may not be a negative number, or an exception will be thrown.
*
* @param int $years [optional] The number of years to subtract.
*
* @return static The DateTime instance for method chaining.
*
* @throws DomainException|Exception Throws an exception on failure.
*/
public function subYears($years = 1) {
// Make sure the years parameter is an integer
if(!is_int($years))
throw new \DomainException('Invalid value for years, must be an integer (\'' . $years . '\' was given)');
// Subtract the number of years, return the result
return $this->addYears($years * -1);
}
/**
* Subtract one, or the given number of years to the date interval.
* The resulting number of years may not be a negative number, or an exception will be thrown.
*
* @param int $years [optional] The number of years to subtract.
*
* @return static The DateTime instance for method chaining.
*
* @throws DomainException|Exception Throws an exception on failure.
*/
public function subYear($years = 1) {
return $this->subYears($years);
}
/**
* Set the number of years.
*
* @param int $years The number of years, must be zero or a positive number.
*
* @return static The DateTime instance for method chaining.
*
* @throws \DomainException Throws an exception on failure.
*/
public function setYears($years) {
// Make sure the value is a positive number or zero
if(!is_int($years) || $years < 0)
throw new \DomainException('Invalid value for years, must be zero or a positive number (\'' . $years .
'\' was given)');
// Set the years, return this instance
$this->y = $years;
return $this;
}
/**
* Get the number of months.
*
* @return int Number of months.
*/
public function getMonths() {
return $this->m;
}
/**
* Add the given number of months to the date interval.
* The resulting number of months may not be a negative number, or an exception will be thrown.
*
* @param int $months [optional] The number of months to add.
*
* @return static The DateTime instance for method chaining.
*
* @throws DomainException|Exception Throws an exception on failure.
*/
public function addMonths($months = 1) {
// Make sure the months parameter is an integer
if(!is_int($months))
throw new DomainException('Invalid value for months, must be an integer (\'' . $months . '\' was given)');
// Calculate the new number of months
$months = $this->getMonths() + intval($months);
// Make sure the number isn't negative
if($months < 0)
throw new Exception('The resulting number of months may not be negative (' . $months . ' is negative)');
// Set the number of months
$this->setMonths($months);
// Return this instance for method chaining
return $this;
}
/**
* Add one, or the given number of months to the date interval.
* The resulting number of months may not be a negative number, or an exception will be thrown.
*
* @param int $months [optional] The number of months to add.
*
* @return static The DateTime instance for method chaining.
*
* @throws DomainException|Exception Throws an exception on failure.
*/
public function addMonth($months = 1) {
return $this->addMonths($months);
}
/**
* Subtract the given number of months to the date interval.
* The resulting number of months may not be a negative number, or an exception will be thrown.
*
* @param int $months [optional] The number of months to subtract.
*
* @return static The DateTime instance for method chaining.
*
* @throws DomainException|Exception Throws an exception on failure.
*/
public function subMonths($months = 1) {
// Make sure the months parameter is an integer
if(!is_int($months))
throw new DomainException('Invalid value for months, must be an integer (\'' . $months . '\' was given)');
// Subtract the number of months, return the result
return $this->addMonths($months * -1);
}
/**
* Subtract one, or the given number of months to the date interval.
* The resulting number of months may not be a negative number, or an exception will be thrown.
*
* @param int $months [optional] The number of months to subtract.
*
* @return static The DateTime instance for method chaining.
*
* @throws DomainException|Exception Throws an exception on failure.
*/
public function subMonth($months = 1) {
return $this->subMonths($months);
}
/**
* Set the number of months.
*
* @param int $months The number of months, must be zero or a positive number.
*
* @return static The DateTime instance for method chaining.
*
* @throws \DomainException Throws an exception on failure.
*/
public function setMonths($months) {
// Make sure the value is a positive number or zero
if(!is_int($months) || $months < 0)
throw new DomainException('Invalid value for months, must be zero or a positive number (\'' . $months .
'\' was given)');
// Set the months, return this instance
$this->m = $months;
return $this;
}
/**
* Add the given number of weeks and days to the date interval.
* The resulting number of days may not be a negative number, or an exception will be thrown.
*
* @param int|null $weeks [optional] The number of weeks to add. Null to ignore this value.
* @param int|null $days [optional] The number of days to add. Null to ignore this value.
*
* @return static The DateTime instance for method chaining.
*
* @throws DomainException|Exception Throws an exception on failure.
*/
public function addWeeksAndDays($weeks = null, $days = null) {
// Calculate the total number of days
$totalDays = 0;
// Append the number of weeks if set
if(is_int($weeks))
$totalDays += intval($weeks) * DateTime::DAYS_PER_WEEK;
else if(!empty($weeks))
throw new DomainException('Invalid value for weeks (\'' . $weeks . '\' was given)');
// Append the number of days if set
if(is_int($days))
$totalDays += intval($days);
else if(!empty($days))
throw new DomainException('Invalid value for days (\'' . $days . '\' was given)');
// Set the number of days
if(!empty($totalDays)) {
// Make sure the number of days isn't negative
if(($this->getDays() + $totalDays) < 0)
throw new DomainException('The resulting number of days may not be below zero (got ' . $totalDays .
' days)');
// Add the number of days
$this->addDays($totalDays);
}
// Return this instance
return $this;
}
/**
* Subtract the given number of weeks and days to the date interval.
* The resulting number of days may not be a negative number, or an exception will be thrown.
*
* @param int|null $weeks [optional] The number of weeks to subtract. Null to ignore this value.
* @param int|null $days [optional] The number of days to subtract. Null to ignore this value.
*
* @return static The DateTime instance for method chaining.
*
* @throws DomainException|Exception Throws an exception on failure.
*/
public function subWeeksAndDays($weeks = null, $days = null) {
// Calculate the total number of days
$totalDays = 0;
// Append the number of weeks if set
if(is_int($weeks))
$totalDays += intval($weeks) * DateTime::DAYS_PER_WEEK;
else if(!empty($weeks))
throw new DomainException('Invalid value for weeks (\'' . $weeks . '\' was given)');
// Append the number of days if set
if(is_int($days))
$totalDays += intval($days);
else if(!empty($days))
throw new DomainException('Invalid value for days (\'' . $days . '\' was given)');
// Set the number of days
if(!empty($totalDays)) {
// Make sure the number of days isn't negative
if(($this->getDays() + $totalDays) < 0)
throw new DomainException('The resulting number of days may not be below zero (got ' . $totalDays .
' days)');
// Subtract the number of days
$this->subDays($totalDays);
}
// Return this instance
return $this;
}
/**
* Set the number of days based ont he given number of weeks and days.
*
* @param int|null $weeks The number of weeks of the interval, this is converted into and added to the number of
* days. Null to ignore this value.
* @param int|null $days The number of days of the interval. Null to ignore this value.
*
* @return static This DateTime instance for method chaining.
*/
public function setWeeksAndDays($weeks = null, $days = null) {
// Calculate the total number of days
$totalDays = 0;
// Append the number of weeks if set
if(is_int($weeks))
$totalDays += intval($weeks) * DateTime::DAYS_PER_WEEK;
else if(!empty($weeks))
throw new DomainException('Invalid value for weeks (\'' . $weeks . '\' was given)');
// Append the number of days if set
if(is_int($days))
$totalDays += intval($days);
else if(!empty($days))
throw new DomainException('Invalid value for days (\'' . $days . '\' was given)');
// Set the number of days
if(!empty($totalDays)) {
// Make sure the number of days isn't negative
if($totalDays < 0)
throw new DomainException('The total number of days may not be below zero (' . $totalDays .
' total days)');
// Set the number of days
$this->setDays($totalDays);
}
// Return this instance
return $this;
}
/**
* Get the approximate number of weeks. This value is based on the number of days specified, and thus isn't exact.
*
* @return int The approximate number of weeks.
*/
public function getApproximateWeeks() {
return (int) ($this->getDays() / DateTime::DAYS_PER_WEEK);
}
/**
* Add the given number of days to the date interval specified as weeks.
* The resulting number of days may not be a negative number, or an exception will be thrown.
*
* @param int $weeks [optional] The number of weeks to add.
*
* @return static The DateTime instance for method chaining.
*
* @throws DomainException|Exception Throws an exception on failure.
*/
public function addWeeks($weeks = 1) {
// Make sure the weeks parameter is an integer
if(!is_int($weeks))
throw new DomainException('Invalid value for weeks, must be an integer (\'' . $weeks . '\' was given)');
// Calculate the new number of days
$days = $this->getDays() + (intval($weeks) * DateTime::DAYS_PER_WEEK);
// Make sure the number isn't negative
if($days < 0)
throw new Exception('The resulting number of days may not be negative (' . $days . ' is negative)');
// Set the number of days
$this->setDays($weeks);
// Return this instance for method chaining
return $this;
}
/**
* Add one, or the given number of days to the date interval specified as weeks.
* The resulting number of days may not be a negative number, or an exception will be thrown.
*
* @param int $weeks [optional] The number of weeks to add.
*
* @return static The DateTime instance for method chaining.
*
* @throws DomainException|Exception Throws an exception on failure.
*/
public function addWeek($weeks = 1) {
return $this->addWeeks($weeks);
}
/**
* Subtract the given number of days to the date interval specified as weeks.
* The resulting number of days may not be a negative number, or an exception will be thrown.
*
* @param int $weeks [optional] The number of weeks to subtract.
*
* @return static The DateTime instance for method chaining.
*
* @throws DomainException|Exception Throws an exception on failure.
*/
public function subWeeks($weeks = 1) {
// Make sure the weeks parameter is an integer
if(!is_int($weeks))
throw new DomainException('Invalid value for weeks, must be an integer (\'' . $weeks . '\' was given)');
// Subtract the number of weeks, return the result
return $this->addWeeks($weeks * -1);
}
/**
* Subtract one, or the given number of days to the date interval specified as weeks.
* The resulting number of days may not be a negative number, or an exception will be thrown.
*
* @param int $weeks [optional] The number of weeks to subtract.
*
* @return static The DateTime instance for method chaining.
*
* @throws DomainException|Exception Throws an exception on failure.
*/
public function subWeek($weeks = 1) {
return $this->subWeeks($weeks);
}
/**
* Set the number of days based on the given number of weeks.
* Note: This will change the number of days.
*
* @param int $weeks The number of weeks, must be zero or a positive number.
*
* @return static The DateTime instance for method chaining.
*
* @throws \DomainException Throws an exception on failure.
*/
public function setWeeks($weeks) {
// Make sure the value is a positive number or zero
if(!is_int($weeks) || $weeks < 0)
throw new DomainException('Invalid value for months, must be zero or a positive number (\'' . $weeks .
'\' was given)');
// Set the days, return this instance
$this->d = $weeks * DateTime::DAYS_PER_WEEK;
return $this;
}
/**
* Get the number of days.
*
* @return int Number of days.
*/
public function getDays() {
return $this->d;
}
/**
* Add the given number of days to the date interval.
* The resulting number of days may not be a negative number, or an exception will be thrown.
*
* @param int $days [optional] The number of days to add.
*
* @return static The DateTime instance for method chaining.
*
* @throws DomainException|Exception Throws an exception on failure.
*/
public function addDays($days = 1) {
// Make sure the days parameter is an integer
if(!is_int($days))
throw new DomainException('Invalid value for days, must be an integer (\'' . $days . '\' was given)');
// Calculate the new number of days
$days = $this->getDays() + intval($days);
// Make sure the number isn't negative
if($days < 0)
throw new Exception('The resulting number of days may not be negative (' . $days . ' is negative)');
// Set the number of days
$this->setDays($days);
// Return this instance for method chaining
return $this;
}
/**
* Add one, or the given number of days to the date interval.
* The resulting number of days may not be a negative number, or an exception will be thrown.
*
* @param int $days [optional] The number of days to add.
*
* @return static The DateTime instance for method chaining.
*
* @throws DomainException|Exception Throws an exception on failure.
*/
public function addDay($days = 1) {
return $this->addDays($days);
}
/**
* Subtract the given number of days to the date interval.
* The resulting number of days may not be a negative number, or an exception will be thrown.
*
* @param int $days [optional] The number of days to subtract.
*
* @return static The DateTime instance for method chaining.
*
* @throws DomainException|Exception Throws an exception on failure.
*/
public function subDays($days = 1) {
// Make sure the days parameter is an integer
if(!is_int($days))
throw new DomainException('Invalid value for days, must be an integer (\'' . $days . '\' was given)');
// Subtract the number of days, return the result
return $this->addDays($days * -1);
}
/**
* Subtract one, or the given number of days to the date interval.
* The resulting number of days may not be a negative number, or an exception will be thrown.
*
* @param int $days [optional] The number of days to subtract.
*
* @return static The DateTime instance for method chaining.
*
* @throws DomainException|Exception Throws an exception on failure.
*/
public function subDay($days = 1) {
return $this->subDays($days);
}
/**
* Set the number of days.
*
* @param int $days The number of days, must be zero or a positive number.
*
* @return static The DateTime instance for method chaining.
*
* @throws DomainException Throws an exception on failure.
*/
public function setDays($days) {
// Make sure the value is a positive number or zero
if(!is_int($days) || $days < 0)
throw new DomainException('Invalid value for days, must be zero or a positive number (\'' . $days .
'\' was given)');
// Set the days, return this instance
$this->d = $days;
return $this;
}
/**
* Add the given number of hours, minutes and seconds to the date interval.
* The resulting values may not be a negative number, or an exception will be thrown.
*
* @param int|null $hours The number of hours to add to the interval. Null to ignore this value.
* @param int|null $minutes The number of minutes to add to the interval. Null to ignore this value.
* @param int|null $seconds The number of seconds to add to the interval. Null to ignore this value.
*
* @return static The DateTime instance for method chaining.
*
* @throws DomainException|Exception Throws an exception on failure.
*/
public function addTime($hours = null, $minutes = null, $seconds = null) {
// Add the number of hours, minutes and seconds if set
if(!empty($hours))
$this->addHours($hours);
if(!empty($minutes))
$this->addMinutes($minutes);
if(!empty($seconds))
$this->addSecond($seconds);
// Return this instance for method chaining
return $this;
}
/**
* Subtract the given number of hours, minutes and seconds to the date interval.
* The resulting values may not be a negative number, or an exception will be thrown.
*
* @param int|null $hours The number of hours to subtract to the interval. Null to ignore this value.
* @param int|null $minutes The number of minutes to subtract to the interval. Null to ignore this value.
* @param int|null $seconds The number of seconds to subtract to the interval. Null to ignore this value.
*
* @return static The DateTime instance for method chaining.
*
* @throws DomainException|Exception Throws an exception on failure.
*/
public function subTime($hours = null, $minutes = null, $seconds = null) {
// Subtract the number of hours, minutes and seconds if set
if(!empty($hours))
$this->subHours($hours);
if(!empty($minutes))
$this->subMinutes($minutes);
if(!empty($seconds))
$this->subSecond($seconds);
// Return this instance for method chaining
return $this;
}
/**
* Set the date and time part of the interval. This changes the specified years, months, days, hours, minutes and
* seconds.
*
* @param int|null $hours The number of hours of the interval. Null to ignore this value.
* @param int|null $minutes The number of minutes of the interval. Null to ignore this value.
* @param int|null $seconds The number of seconds of the interval. Null to ignore this value.
*
* @return static This DateInterval instance for method chaining.
*/
public function setTime($hours = null, $minutes = null, $seconds = null) {
// Set the hours, minutes and seconds
if(!empty($hours))
$this->setHours($hours);
if(!empty($minutes))
$this->setMinutes($minutes);
if(!empty($seconds))
$this->setSeconds($seconds);
// Return this instance
return $this;
}
/**
* Get the number of hours.
*
* @return int Number of hours.
*/
public function getHours() {
return $this->h;
}
/**
* Add the given number of hours to the date interval.
* The resulting number of hours may not be a negative number, or an exception will be thrown.
*
* @param int $hours [optional] The number of hours to add.
*
* @return static The DateTime instance for method chaining.
*
* @throws DomainException|Exception Throws an exception on failure.
*/
public function addHours($hours = 1) {
// Make sure the hours parameter is an integer
if(!is_int($hours))
throw new DomainException('Invalid value for hours, must be an integer (\'' . $hours . '\' was given)');
// Calculate the new number of hours
$hours = $this->getHours() + intval($hours);
// Make sure the number isn't negative
if($hours < 0)
throw new Exception('The resulting number of hours may not be negative (' . $hours . ' is negative)');
// Set the number of hours
$this->setHours($hours);
// Return this instance for method chaining
return $this;
}
/**
* Add one, or the given number of hours to the date interval.
* The resulting number of hours may not be a negative number, or an exception will be thrown.
*
* @param int $hours [optional] The number of hours to add.
*
* @return static The DateTime instance for method chaining.
*
* @throws DomainException|Exception Throws an exception on failure.
*/
public function addHour($hours = 1) {
return $this->addHours($hours);
}
/**
* Subtract the given number of hours to the date interval.
* The resulting number of hours may not be a negative number, or an exception will be thrown.
*
* @param int $hours [optional] The number of hours to subtract.
*
* @return static The DateTime instance for method chaining.
*
* @throws DomainException|Exception Throws an exception on failure.
*/
public function subHours($hours = 1) {
// Make sure the hours parameter is an integer
if(!is_int($hours))
throw new DomainException('Invalid value for hours, must be an integer (\'' . $hours . '\' was given)');
// Subtract the number of hours, return the result
return $this->addHours($hours * -1);
}
/**
* Subtract one, or the given number of hours to the date interval.
* The resulting number of hours may not be a negative number, or an exception will be thrown.
*
* @param int $hours [optional] The number of hours to subtract.
*
* @return static The DateTime instance for method chaining.
*
* @throws DomainException|Exception Throws an exception on failure.
*/
public function subHour($hours = 1) {
return $this->subHours($hours);
}
/**
* Set the number of hours.
*
* @param int $hours The number of hours, must be zero or a positive number.
*
* @return static The DateTime instance for method chaining.
*
* @throws \DomainException Throws an exception on failure.
*/
public function setHours($hours) {
// Make sure the value is a positive number or zero
if(!is_int($hours) || $hours < 0)
throw new DomainException('Invalid value for hours, must be zero or a positive number (\'' . $hours .
'\' was given)');
// Set the hours, return this instance
$this->h = $hours;
return $this;
}
/**
* Get the number of minutes.
*
* @return int Number of minutes.
*/
public function getMinutes() {
return $this->i;
}
/**
* Add the given number of minutes to the date interval.
* The resulting number of minutes may not be a negative number, or an exception will be thrown.
*
* @param int $minutes [optional] The number of minutes to add.
*
* @return static The DateTime instance for method chaining.
*
* @throws DomainException|Exception Throws an exception on failure.
*/
public function addMinutes($minutes = 1) {
// Make sure the minutes parameter is an integer
if(!is_int($minutes))
throw new DomainException('Invalid value for minutes, must be an integer (\'' . $minutes . '\' was given)');
// Calculate the new number of minutes
$minutes = $this->getMinutes() + intval($minutes);
// Make sure the number isn't negative
if($minutes < 0)
throw new Exception('The resulting number of minutes may not be negative (' . $minutes . ' is negative)');
// Set the number of minutes
$this->setMinutes($minutes);
// Return this instance for method chaining
return $this;
}
/**
* Add one, or the given number of minutes to the date interval.
* The resulting number of minutes may not be a negative number, or an exception will be thrown.
*
* @param int $minutes [optional] The number of minutes to add.
*
* @return static The DateTime instance for method chaining.
*
* @throws DomainException|Exception Throws an exception on failure.
*/
public function addMinute($minutes = 1) {
return $this->addMinutes($minutes);
}
/**
* Subtract the given number of minutes to the date interval.
* The resulting number of minutes may not be a negative number, or an exception will be thrown.
*
* @param int $minutes [optional] The number of minutes to subtract.
*
* @return static The DateTime instance for method chaining.
*
* @throws DomainException|Exception Throws an exception on failure.
*/
public function subMinutes($minutes = 1) {
// Make sure the minutes parameter is an integer
if(!is_int($minutes))
throw new DomainException('Invalid value for minutes, must be an integer (\'' . $minutes .
'\' was given)');
// Subtract the number of minutes, return the result
return $this->addMinutes($minutes * -1);
}
/**
* Subtract one, or the given number of minutes to the date interval.
* The resulting number of minutes may not be a negative number, or an exception will be thrown.
*
* @param int $minutes [optional] The number of minutes to subtract.
*
* @return static The DateTime instance for method chaining.
*
* @throws DomainException|Exception Throws an exception on failure.
*/
public function subMinute($minutes = 1) {
return $this->subMinutes($minutes);
}
/**
* Set the number of minutes.
*
* @param int $minutes The number of minutes, must be zero or a positive number.
*
* @return static The DateTime instance for method chaining.
*
* @throws \DomainException Throws an exception on failure.
*/
public function setMinutes($minutes) {
// Make sure the value is a positive number or zero
if(!is_int($minutes) || $minutes < 0)
throw new DomainException('Invalid value for minutes, must be zero or a positive number (\'' . $minutes .
'\' was given)');
// Set the minutes, return this instance
$this->i = $minutes;
return $this;
}
/**
* Get the number of seconds.
*
* @return int Number of seconds.
*/
public function getSeconds() {
return $this->s;
}
/**
* Add the given number of seconds to the date interval.
* The resulting number of seconds may not be a negative number, or an exception will be thrown.
*
* @param int $seconds [optional] The number of seconds to add.
*
* @return static The DateTime instance for method chaining.
*
* @throws DomainException|Exception Throws an exception on failure.
*/
public function addSeconds($seconds = 1) {
// Make sure the seconds parameter is an integer
if(!is_int($seconds))
throw new DomainException('Invalid value for seconds, must be an integer (\'' . $seconds . '\' was given)');
// Calculate the new number of seconds
$seconds = $this->getSeconds() + intval($seconds);
// Make sure the number isn't negative
if($seconds < 0)
throw new Exception('The resulting number of seconds may not be negative (' . $seconds . ' is negative)');
// Set the number of seconds
$this->setSeconds($seconds);
// Return this instance for method chaining
return $this;
}
/**
* Add one, or the given number of seconds to the date interval.
* The resulting number of seconds may not be a negative number, or an exception will be thrown.
*
* @param int $seconds [optional] The number of seconds to add.
*
* @return static The DateTime instance for method chaining.
*
* @throws DomainException|Exception Throws an exception on failure.
*/
public function addSecond($seconds = 1) {
return $this->addSeconds($seconds);
}
/**
* Subtract the given number of seconds to the date interval.
* The resulting number of seconds may not be a negative number, or an exception will be thrown.
*
* @param int $seconds [optional] The number of seconds to subtract.
*
* @return static The DateTime instance for method chaining.
*
* @throws DomainException|Exception Throws an exception on failure.
*/
public function subSeconds($seconds = 1) {
// Make sure the seconds parameter is an integer
if(!is_int($seconds))
throw new DomainException('Invalid value for seconds, must be an integer (\'' . $seconds .
'\' was given)');
// Subtract the number of seconds, return the result
return $this->addSeconds($seconds * -1);
}
/**
* Subtract one, or the given number of seconds to the date interval.
* The resulting number of seconds may not be a negative number, or an exception will be thrown.
*
* @param int $seconds [optional] The number of seconds to subtract.
*
* @return static The DateTime instance for method chaining.
*
* @throws DomainException|Exception Throws an exception on failure.
*/
public function subSecond($seconds = 1) {
return $this->subSeconds($seconds);
}
/**
* Set the number of seconds.
*
* @param int $seconds The number of seconds, must be zero or a positive number.
*
* @return static The DateTime instance for method chaining.
*
* @throws \DomainException Throws an exception on failure.
*/
public function setSeconds($seconds) {
// Make sure the value is a positive number or zero
if(!is_int($seconds) || $seconds < 0)
throw new DomainException('Invalid value for seconds, must be zero or a positive number (\'' . $seconds .
'\' was given)');
// Set the seconds, return this instance
$this->s = $seconds;
return $this;
}
/**
* Check whether the date interval is inverted.
*
* @return bool True if the date interval is inverted, false if not.
*/
public function isInverted() {
return $this->invert !== 0;
}
/**
* Set whether the date interval is inverted.
*
* @param int|bool $inverted One or true if the date interval is inverted, zero or false if not.
*
* @return static This DateInterval instance.
*/
public function setInverted($inverted) {
// Parse the parameter value
$inverted = empty($inverted) ? 0 : 1;
// Set whether the interval is inverted, return this instance
$this->invert = $inverted;
return $this;
}
/**
* Get the day span of this interval. This only works for objects created with DateTime::diff().
*
* @return int|null The day span of this interval, or null on failure.
*/
public function getDaySpan() {
return $this->isCreatedFromDiff() ? $this->days : null;
}
/**
* Check whether this is a zero date interval.
*
* @return bool True if this date interval is zero, false if not.
*/
public function isZero() {
return ($this->getYears() == 0 && $this->getMonths() == 0 && $this->getDays() == 0 &&
$this->getHours() == 0 && $this->getMinutes() == 0 && $this->getSeconds() == 0);
}
/**
* Check whether this date time object was created using DateTime::diff() or PHPDateTime::diff().
*
* @return bool True if this date interval object was created by a diff() method, false if not. If the date
* interval isn't an instance of DateInterval false will also be returned.
*/
public function isCreatedFromDiff() {
return DateIntervalUtils::isCreatedFromDiff($this);
}
/**
* Add the passed interval of the current instance
*
* @param PHPDateInterval|PHPDateInterval|string|null $dateInterval The DateInterval or PHPDateInterval instance,
* the date interval specification as a string or null to use a zero specification.
*
* @return static|null This DateInterval instance for method chaining, or null on failure.
*/
public function add($dateInterval) {
// Parse the date interval, return null on failure
if(($dateInterval = static::parse($dateInterval)) === null)
return null;
// Calculate the factor to multiply each value with
$factor = $dateInterval->isInverted() ? -1 : 1;
/*if(DateIntervalUtils::isCreatedFromDiff($dateInterval))
$this->setDays($this->getDays() + ($dateInterval->getDaySpan() * $factor));
else*/
// Add the date and time
$this->addDateTime($dateInterval->getYears() * $factor, $dateInterval->getMonths() * $factor, null,
$dateInterval->getDays() * $factor, $dateInterval->getHours() * $factor,
$dateInterval->getMinutes() * $factor, $dateInterval->getSeconds() * $factor);
// Return this instance
return $this;
}
/**
* Subtract the passed interval of the current instance.
*
* @param PHPDateInterval|PHPDateInterval|string|null $dateInterval The DateInterval or PHPDateInterval instance,
* the date interval specification as a string or null to use a zero specification.
*
* @return static|null This DateInterval instance for method chaining, or null on failure.
*/
public function sub($dateInterval) {
// Parse the date interval as a new instance, return null on failure
if(($dateInterval = static::instance($dateInterval)) === null)
return null;
// Invert the date interval
$dateInterval->setInverted(!$dateInterval->isInverted());
// Subtract and return the result
return $this->add($dateInterval);
}
/**
* Create a ISO-8601 date interval specification string.
*
* @return string The date interval specification string.
*/
public function toSpecString() {
return DateIntervalSpecUtils::create($this->getYears(), $this->getMonths(), null, $this->getDays(),
$this->getHours(), $this->getMinutes(), $this->getSeconds());
}
/**
* Get the date interval as a string.
*
* @return string The date interval string.
*/
public function toString() {
return $this->toSpecString();
}
// TODO: toString() for humans!
/**
* Get the date interval as a string.
*
* @return string The date interval string.
*/
public function __toString() {
return ($result = $this->toString()) === null ? '' : $result;
}
// TODO: Create a wrapper for createFromDateString();
/*
/**
* Get a date interval attribute.
*
* @param string $name The name of the attribute to get.
*
* @return int The value of the getter.
*
* @throws \InvalidArgumentException Throws an exception on failure.
* /
public function __get($name) {
// Get the number of years
if(StringUtils::equals($name, 'years', true))
return $this->getYears();
// Get the number of months
if(StringUtils::equals($name, 'months', true))
return $this->getMonths();
// Get the number of days
if(StringUtils::equals($name, 'days', true))
return $this->getDays();
// Get the number of hours
if(StringUtils::equals($name, 'hours', true))
return $this->getHours();
// Get the number of minutes
if(StringUtils::equals($name, 'minutes', true))
return $this->getMinutes();
// Get the number of seconds
if(StringUtils::equals($name, 'seconds', true))
return $this->getSeconds();
switch($name) {
case 'weeks':
return (int) floor($this->d / DateTime::DAYS_PER_WEEK);
case 'daysExcludeWeeks':
return $this->d % DateTime::DAYS_PER_WEEK;
default:
throw new \InvalidArgumentException('Unknown getter \'' . $name . '\'');
}
}
/**
* Set an attribute of the date interval object.
*
* @param string $name The name of the attribute to set.
* @param int $value The value to set the attribute to.
*
* @return static The DateTime instance.
*
* @throws \InvalidArgumentException Throw an exception on failure.
* /
public function __set($name, $value) {
// Set the number of years
if(StringUtils::equals($name, 'years', true))
return $this->setYears($value);
// Set the number of months
if(StringUtils::equals($name, 'months', true))
return $this->setMonths($value);
// Set the number of days
if(StringUtils::equals($name, 'days', true))
return $this->setDays($value);
// Set the number of hours
if(StringUtils::equals($name, 'hours', true))
return $this->setHours($value);
// Set the number of minutes
if(StringUtils::equals($name, 'minutes', true))
return $this->setMInutes($value);
// Set the number of seconds
if(StringUtils::equals($name, 'seconds', true))
return $this->setSeconds($value);
switch ($name) {
case 'weeks':
$this->d = $value * DateTime::DAYS_PER_WEEK;
break;
}
}
/**
* Allow fluent calls on the setters. CarbonInterval::years(3)->months(5)->day().
*
* Note: This is done using the magic method to allow static and instance methods to have the same names.
*
* @param string $name The name of the method being called.
* @param Array $args An array of method parameters.
*
* @return static The DateTime instance, which could be used for method chaining.
* /
public function __call($name, $args) {
// Get the delimiter value
$arg = count($args) == 0 ? 1 : $args[0];
// Handle the years setter
if(StringUtils::equals($name, Array('years', 'year'), true)) {
$this->years = $arg;
return $this;
}
// Handle the months setter
if(StringUtils::equals($name, Array('months', 'month'), true)) {
$this->months = $arg;
return $this;
}
// Handle the weeks setter
if(StringUtils::equals($name, Array('weeks', 'week'), true)) {
$this->days = $arg * DateTime::DAYS_PER_WEEK;
return $this;
}
// Handle the days setter
if(StringUtils::equals($name, Array('days', 'day'), true)) {
$this->days = $arg;
return $this;
}
// Handle the hours setter
if(StringUtils::equals($name, Array('hours', 'hour'), true)) {
$this->hours = $arg;
return $this;
}
// Handle the minutes setter
if(StringUtils::equals($name, Array('minutes', 'minute'), true)) {
$this->minutes = $arg;
return $this;
}
// Handle the seconds setter
if(StringUtils::equals($name, Array('seconds', 'second'), true)) {
$this->seconds = $arg;
return $this;
}
// Return this instance
return $this;
}
/**
* Provide static helpers to create instances.
* Allows CarbonInterval::years(3).
*
* Note: This is done using the magic method to allow static and instance methods to have the same names.
*
* @param string $name The name of the static method being called.
* @param Array $args An array of method parameters.
*
* @return static The DateInterval instance.
* /
public static function __callStatic($name, $args) {
// Get the delimiter value if any argument has been given
$delimiterValue = count($args) == 0 ? 1 : $args[0];
// Handle the years delimiter
if(StringUtils::equals($name, Array('years', 'year'), true))
return DateIntervalFactory::create($delimiterValue);
// Handle the months delimiter
if(StringUtils::equals($name, Array('months', 'month'), true))
return DateIntervalFactory::create(null, $delimiterValue);
// Handle the weeks delimiter
if(StringUtils::equals($name, Array('weeks', 'week'), true))
return DateIntervalFactory::create(null, null, $delimiterValue);
// Handle the days delimiter
if(StringUtils::equals($name, Array('days', 'day'), true))
return DateIntervalFactory::create(null, null, null, $delimiterValue);
// Handle the hours delimiter
if(StringUtils::equals($name, Array('hours', 'hour'), true))
return DateIntervalFactory::create(null, null, null, null, $delimiterValue);
// Handle the minutes delimiter
if(StringUtils::equals($name, Array('minutes', 'minute'), true))
return DateIntervalFactory::create(null, null, null, null, null, $delimiterValue);
// Handle the seconds delimiter
if(StringUtils::equals($name, Array('seconds', 'second'), true))
return DateIntervalFactory::create(null, null, null, null, null, null, $delimiterValue);
}
*/
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment