use \DateTime; // http://php.net/manual/en/class.datetime.php
7 years ago
use \DateInterval; // http://php.net/manual/en/class.dateinterval.php
use \DateTimeZone; // http://php.net/manual/en/class.datetimezone.php
7 years ago
//use \DatePeriod; // http://php.net/manual/en/class.dateperiod.php // I don't extend this class, because the `start`, `current` and `end` are private, so I don't have access to them!
7 years ago
7 years ago
use \Iterator; // http://php.net/manual/en/class.iteratoraggregate.php Interface to create an external Iterator.
7 years ago
7 years ago
class DatePeriod implements Iterator
7 years ago
{
7 years ago
private $start = null;
private $current = null;
private $end = null;
private $interval = null;
7 years ago
7 years ago
public static $utc = null;
public static $p1d = null;
/**
* @param string|DateTime $start start date
* @param string|DateTime $param1 end date or interval
* @param string|DateTime $param2 interval or end date
* @return void
*/
public function __construct($start, $param1 = null, $param2 = null)
{
if (is_string($start))
{
$this->start = new \DateTime($start, self::$utc); // all roads are lead to this ...
/*
if (strlen($start) === 10 && preg_match('~\d\d\d\d-\d\d-\d\d~', $start) === 1)
{
$this->start = new \DateTime($start, self::$utc);
}
else if (preg_match('~\d\d\d\d-\d\d-\d\d~', $start) === 1) // more relaxed ... basically the same as above, leaving this here incase I don't support `time` component in the future! Currently, because I support the `time` component, the top is not necessary, only this one! I was going to do this: preg_match('~(\d\d\d\d)-(\d\d)-(\d\d)~', $param1, $matches) and extract the date, but I curently don't care!
{
$this->start = new \DateTime($start, self::$utc);
}
else
{
$this->start = new \DateTime($start, self::$utc);
}
*/
}
else if ($start instanceof \Twister\DateTime || $start instanceof \Twister\Date)
{
$this->start = new \DateTime((string) $start, self::$utc);
}
else if ($start instanceof \DateTime)
{
$this->start = $start;
}
else if (is_object($start))
{
if ( ! method_exists($start, '__toString'))
throw new InvalidArgumentException('Starting date object must have a __toString method');
$this->start = new \DateTime((string) $start, self::$utc);
}
else
{
throw new InvalidArgumentException(sprintf(
'Invalid type passed to DatePeriod constructor in $start parameter; expecting a string or DateTime object, received "%s"',
if (preg_match('~\d\d\d\d-\d\d-\d\d~', $param1) === 1)
{
$this->end = new \DateTime($param1, self::$utc);
if ($param2 === null)
{ // fast test for the most likely param2 value ... just to return faster!
$this->interval = self::$p1d;
return;
}
$this->interval = $param2;
}
else if (strtotime($param1) !== false)
{
// $this->end = new \DateTime(strtotime($param1, $this->start->getTimestamp()), self::$utc);
$this->end = DateTime::createFromFormat('U', strtotime($param1, $this->start->getTimestamp()), self::$utc); // not working 100% for fixed dates like '27 January 2017' returns '2017-01-26'
if ($param2 === null)
{ // fast test for the most likely param2 value ... just to return faster!
$this->interval = self::$p1d;
return;
}
$this->interval = $param2;
}
else if ($param1 !== '' && $param1[0] === 'P')
{
$this->interval = new \DateInterval($param1);
$this->end = $param2;
}
else
{
throw new InvalidArgumentException(
"Invalid value passed to DatePeriod constructor in \$param1; expecting a valid DateTime string or DateInterval string, received `{$param1}`"
);
}
}
else if ($param1 === null)
{
$this->end = new \DateTime('9999-12-31', self::$utc);
$this->interval = self::$p1d;
return;
}
else if ($param1 instanceof \Twister\DateTime)
{
$this->end = new \DateTime((string) $param1, self::$utc);
if ($param2 === null)
{ // fast test for the most likely param2 value ... just to return faster!
$this->interval = self::$p1d;
return;
}
$this->interval = $param2;
}
else if ($param1 instanceof \DateTime)
{
$this->end = $param1;
if ($param2 === null)
{ // fast test for the most likely param2 value ... just to return faster!
$this->interval = self::$p1d;
return;
}
$this->interval = $param2;
}
else if ($param1 instanceof \DateInterval)
{
$this->interval = $param1;
$this->end = $param2;
}
else if (is_object($param1))
{
if ( ! method_exists($param1, '__toString'))
throw new InvalidArgumentException('Starting date object must have a __toString method');
$this->end = new \DateTime((string) $param1, self::$utc);
}
else
{
throw new InvalidArgumentException(sprintf(
'Invalid type passed to DatePeriod constructor in $param1 parameter; expecting a string or DateTime object, received "%s"',
$this->end = new \DateTime('9999-12-31', self::$utc);
}
else if (is_string($this->end))
{
if (preg_match('~\d\d\d\d-\d\d-\d\d~', $this->end) === 1)
{
$this->end = new \DateTime($this->end, self::$utc);
}
else if (strtotime($this->end) !== false)
{
// $this->end = new \DateTime(strtotime($this->end, $this->start->getTimestamp()), self::$utc);
$this->end = DateTime::createFromFormat('U', strtotime($param1, $this->start->getTimestamp()), self::$utc); // not working 100% for fixed dates like '27 January 2017' returns '2017-01-26'
}
else
{
throw new InvalidArgumentException(
"Invalid value passed to DatePeriod constructor for end date; expecting a valid DateTime string or DateInterval string, received `{$this->end}`"
);
}
}
else if ($this->end instanceof \Twister\DateTime)
{
$this->end = new \DateTime((string) $this->end, self::$utc);
}
else if (is_object($this->end))
{
if ( ! method_exists($this->end, '__toString'))
throw new InvalidArgumentException('End date object must have a __toString method');
$this->end = new \DateTime((string) $this->end, self::$utc);
}
else
{
throw new InvalidArgumentException(sprintf(
'Invalid type passed to DatePeriod constructor for end date; expecting a valid DateTime object or string, received "%s"',
case 'dayname': return $this->current->format('l'); // https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_dayname MySQL: Returns the name of the weekday for date. The language used for the name is controlled by the value of the lc_time_names system variable
case 'dayofmonth': return $this->current->format('j'); // https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_dayofmonth MySQL: Returns the day of the month for date, in the range 1 to 31, or 0 for dates such as '0000-00-00' or '2008-00-00' that have a zero day part.
case 'dayofyear': return $this->current->format('z') + 1; // https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_dayofyear MySQL: Returns the day of the year for date, in the range 1 to 366.
case 'monthname': return $this->current->format('F'); // https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_monthname MySQL: Returns the full name of the month for date. The language used for the name is controlled by the value of the lc_time_names system variable
case 'timestamp': return $this->current->format('U'); // https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_timestamp MySQL: With a single argument, this function returns the date or datetime expression expr as a datetime value. With two arguments, it adds the time expression expr2 to the date or datetime expression expr1 and returns the result as a datetime value.
case 'unix_timestamp': return $this->current->format('U'); // https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_unix-timestamp MySQL: If called with no argument, returns a Unix timestamp (seconds since '1970-01-01 00:00:00' UTC).
case 'to_days': break; // https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_to-days MySQL: Given a date date, returns a day number (the number of days since year 0).
case 'utc_date': return $this->current->format('Y-m-d'); // https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_utc-date MySQL: Returns the current UTC date as a value in 'YYYY-MM-DD' or YYYYMMDD format, depending on whether the function is used in a string or numeric context.
case 'utc_time': return $this->current->format('H:i:s'); // https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_utc-time MySQL: Returns the current UTC time as a value in 'HH:MM:SS'
case 'utc_timestamp': return $this->current->format('Y-m-d H:i:s'); // https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_utc-timestamp MySQL: Returns the current UTC date and time as a value in 'YYYY-MM-DD HH:MM:SS' or YYYYMMDDHHMMSS format, depending on whether the function is used in a string or numeric context.
case 'quarter': return $this->current->format('m') / 4 + 1; // https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_quarter MySQL: Returns the quarter of the year for date, in the range 1 to 4.
case 'week': break; // https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_week MySQL: This function returns the week number for date. The two-argument form of WEEK() enables you to specify whether the week starts on Sunday or Monday and whether the return value should be in the range from 0 to 53 or from 1 to 53. If the mode argument is omitted, the value of the default_week_format system variable is used. See Section 5.1.5, “Server System Variables”.
case 'weekday': return $this->current->format('N') - 1; // https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_weekday MySQL: Returns the weekday index for date (0 = Monday, 1 = Tuesday, … 6 = Sunday).
case 'weekofyear': break; // https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_weekofyear MySQL: Returns the calendar week of the date as a number in the range from 1 to 53. WEEKOFYEAR() is a compatibility function that is equivalent to WEEK(date,3).
case 'yearweek': break; // https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_yearweek MySQL: Returns year and week for a date. The year in the result may be different from the year in the date argument for the first and the last week of the year.
case 'date': return $this->current->format('Y-m-d'); // https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_date MySQL: Extracts the date part of the date or datetime expression expr.
throw new \Exception('TODO: Property __get(`' . $name . '`) not implemented yet');
// strtolower($name) versions
case 'year': return $this->current->format('Y');
case 'month': return $this->current->format('m');
case 'day': return $this->current->format('d');
case 'hour': return $this->current->format('G'); // https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_hour MySQL: Returns the hour for time. The range of the return value is 0 to 23 for time-of-day values. However, the range of TIME values actually is much larger, so HOUR can return values greater than 23.
case 'minute': return $this->current->format('i'); // https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_minute MySQL: Returns the minute for time, in the range 0 to 59.
case 'second': return $this->current->format('s'); // https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_hour MySQL: Returns the second for time, in the range 0 to 59.
}
}
function __set($name, $value)
{
switch ($name)
{
case 'current':
if (is_string($value)) {
$this->current = new \DateTime($value, self::$utc); // all roads lead to this ...
}
else if ($value instanceof \Twister\DateTime || $value instanceof \Twister\Date) {
$this->current = new \DateTime((string) $value, self::$utc);
}
else if ($value instanceof \DateTime) {
$this->current = $value;
}
else if (is_object($value)) {
if ( ! method_exists($value, '__toString'))
throw new InvalidArgumentException('Current date object must have a __toString method');
$this->current = new \DateTime((string) $value, self::$utc);
}
else {
throw new InvalidArgumentException(sprintf(
'Invalid type passed to __set(`' . $name . '`); expecting a string or DateTime object, received "%s"',