Check if a date is between two others with jockers
<?php
class checkRule
{
/**
* check if $datetime is between the start date and end date of a rule
*
* $rule has this format :
* array(
* 'date_start' => 'YYYY-MM-DD HH:MM:SS',
* 'date_end' => 'YYYY-MM-DD HH:MM:SS',
* );
*
* year and second of datetime are ignored
* 00 for month or day means *
*
* @param array $rule
* @param string/boolean $datetime when to valid the rule, if false current time is used
* @return boolean
*/
function isRuleValid($rule, $datetime = false)
{
$timetoCheck = $datetime ? strtotime($datetime) : time();
list($date, $time) = explode(' ', $rule['date_start']);
list($start['year'], $start['month'], $start['day']) = explode('-', $date);
if ($start['month'] == 0) $start['month'] = null;
if ($start['day'] == 0) $start['day'] = null;
list($start['hour'], $start['minute'], $start['second']) = explode(':', $time);
list($date, $time) = explode(' ', $rule['date_end']);
list($end['year'], $end['month'], $end['day']) = explode('-', $date);
if ($end['month'] == 0) $end['month'] = null;
if ($end['day'] == 0) $end['day'] = null;
list($end['hour'], $end['minute'], $end['second']) = explode(':', $time);
$startPrev = $this->getPrevRun($timetoCheck, $start);
$startNext = $this->getNextRun($timetoCheck, $start);
$endPrev = $this->getPrevRun($timetoCheck, $end);
$endNext = $this->getNextRun($timetoCheck, $end);
return (($endPrev < $startPrev) && ($startNext > $endNext));
}
/**
* Find the next time a job should be executed
* http://stackoverflow.com/questions/321494/calculate-when-a-cron-job-will-be-executed-then-next-time/
*
* $job has this format :
* array(
* 'minute' => integer or null,
* 'hour' => integer or null,
* 'day' => integer or null,
* 'month' => integer or null
* );
* null means '*'
*
* @param array $job
* @return int timestamp of the next execution
*/
function getNextRun($time, $job)
{
$job = $this->correctJob($job);
$cron = new simpleTimestamp($time);
$done = 0;
while ($done < 100)
{
if (!is_null($job['minute']) && ($cron->minute != $job['minute']))
{
if ($cron->minute > $job['minute'])
{
$cron->modify('+1 hour');
}
$cron->minute = $job['minute'];
}
if (!is_null($job['hour']) && ($cron->hour != $job['hour']))
{
if ($cron->hour > $job['hour'])
{
$cron->modify('+1 day');
}
$cron->hour = $job['hour'];
$cron->minute = 0;
}
if (!is_null($job['day']) && ($cron->day != $job['day']))
{
if ($cron->day > $job['day'])
{
$cron->modify('+1 month');
}
$cron->day = $job['day'];
$cron->hour = 0;
$cron->minute = 0;
}
if (!is_null($job['month']) && ($cron->month != $job['month']))
{
if ($cron->month > $job['month'])
{
$cron->modify('+1 year');
}
$cron->month = $job['month'];
$cron->day = 1;
$cron->hour = 0;
$cron->minute = 0;
}
$done = (is_null($job['minute']) || $job['minute'] == $cron->minute)
&& (is_null($job['hour']) || $job['hour'] == $cron->hour)
&& (is_null($job['day']) || $job['day'] == $cron->day)
&& (is_null($job['month']) || $job['month'] == $cron->month)
? 100 : ($done + 1);
}
return $cron->timestamp;
}
/**
* Find the previous time a job should have been executed
* http://stackoverflow.com/questions/321494/calculate-when-a-cron-job-will-be-executed-then-next-time/
*
* $job has this format :
* array(
* 'minute' => integer or null,
* 'hour' => integer or null,
* 'day' => integer or null,
* 'month' => integer or null
* );
* null means '*'
*
* @param array $job
* @return int timestamp of the next execution
*/
function getPrevRun($time, $job)
{
$job = $this->correctJob($job);
$cron = new simpleTimestamp($time);
$done = 0;
while ($done < 100)
{
if (!is_null($job['month']) && ($cron->month != $job['month']))
{
if ($cron->month < $job['month'])
{
$cron->modify('-1 year');
}
$cron->month = $job['month'];
$cron->day = (int)date('d', mktime(0, 0, 0, $cron->month + 1, 0, $cron->year));
$cron->hour = 23;
$cron->minute = 59;
}
if (!is_null($job['day']) && ($cron->day != $job['day']))
{
if ($cron->day < $job['day'])
{
$cron->modify('-1 month');
}
$cron->day = $job['day'];
$cron->hour = 23;
$cron->minute = 59;
}
if (!is_null($job['hour']) && ($cron->hour != $job['hour']))
{
if ($cron->hour < $job['hour'])
{
$cron->modify('-1 day');
}
$cron->hour = $job['hour'];
$cron->minute = 59;
}
if (!is_null($job['minute']) && ($cron->minute != $job['minute']))
{
if ($cron->minute < $job['minute'])
{
$cron->modify('-1 hour');
}
$cron->minute = $job['minute'];
}
$done = (is_null($job['minute']) || $job['minute'] == $cron->minute)
&& (is_null($job['hour']) || $job['hour'] == $cron->hour)
&& (is_null($job['day']) || $job['day'] == $cron->day)
&& (is_null($job['month']) || $job['month'] == $cron->month) ? 100 : ($done + 1);
}
return $cron->timestamp;
}
/**
* Correct invalid job
* For example 31/02 25:63 become 03/03 02:03
*
* $job has this format :
* array(
* 'minute' => integer or null,
* 'hour' => integer or null,
* 'day' => integer or null,
* 'month' => integer or null
* );
* null means '*'
*
* @param array $job
* @return array job valid
*/
function correctJob($job)
{
if ((int)$job['minute'] > 59)
{
if ($job['hour'] !== null) $job['hour']+= (int)($job['minute'] / 60);
$job['minute']%= 60;
}
if ((int)$job['hour'] > 23)
{
if ($job['day'] !== null) $job['day']+= (int)($job['hour'] / 24);
$job['hour']%= 24;
}
if ((int)$job['day'] > 29)
{
if ($job['month'] !== null)
{
$max = (int)date('d', mktime(0, 0, 0, $job['month'] + 1, 0));
$job['month']+= (int)($job['day'] / $max);
$job['day'] = 1 + (int)($job['day'] % ($max + 1));
}
else $job['hour']%= 31 + 1;
}
if ((int)$job['month'] > 11)
{
$job['month'] = ($job['month'] % 12);
}
return $job;
}
}
/**
* Allows to use timestamp easily
*
* properties are:
* - second
* - minute
* - hour
* - day
* - month
* - year
* - timestamp
*/
class simpleTimestamp
{
private var $current_timestamp;
private static $dateComponent = array(
'second' => 's',
'minute' => 'i',
'hour' => 'G',
'day' => 'j',
'month' => 'n',
'year' => 'Y',
'timestamp' => 'U'
);
function __construct($timestamp = NULL)
{
$this->current_timestamp = is_null($timestamp) ? time() : $timestamp;
}
function __set($var, $value)
{
$components = array();
list( $components['second'],
$components['minute'],
$components['hour'],
$components['day'],
$components['month'],
$components['year']
) = explode(' ', date('s i G j n Y', $this->current_timestamp));
switch ($var)
{
case 'timestamp':
$this->current_timestamp = $value;
break;
default:
$components[$var] = $value;
$this->current_timestamp = mktime(
$components['hour'],
$components['minute'],
$components['second'],
$components['month'],
$components['day'],
$components['year']
);
}
}
function __get($var)
{
if (array_key_exists(self::$dateComponent, $var)) {
$result = date(self::$dateComponent[$var], $this->current_timestamp);
} else {
$result = false;
}
return $result;
}
/**
* Modify the time using strtotime
* http://php.net/strtotime
*
* @param string $how can by '+1 week 2 days 4 hours 2 seconds', '10 September 2000' or 'now'
*/
function modify($how)
{
return $this->current_timestamp = strtotime($how, $this->current_timestamp);
}
}
$tmp = new checkRule();
$rule = array(
'date_start' => '0000-00-00 19:00:00',
'date_end' => '0000-00-00 18:00:00',
);
$tmp->isRuleValid($rule, '2012-05-04 15:00:00'); // true
$tmp->isRuleValid($rule, '2012-05-04 18:30:00'); // false
$rule = array(
'date_start' => '0000-03-20 0:00:00',
'date_end' => '0000-05-00 0:00:00',
);
$tmp->isRuleValid($rule, '2012-04-26 18:30:00'); // true
$tmp->isRuleValid($rule, '2012-05-04 18:30:00'); // false
$rule = array(
'date_start' => '0000-11-20 0:00:00',
'date_end' => '0000-02-00 0:00:00',
);
$tmp->isRuleValid($rule, '2012-01-01 00:00:00'); // true
$tmp->isRuleValid($rule, '2012-10-01 00:00:00'); // false
?>