update v1.0.6
This commit is contained in:
13
vendor/mtdowling/cron-expression/README.md
vendored
13
vendor/mtdowling/cron-expression/README.md
vendored
@@ -68,15 +68,4 @@ Requirements
|
||||
|
||||
- PHP 5.3+
|
||||
- PHPUnit is required to run the unit tests
|
||||
- Composer is required to run the unit tests
|
||||
|
||||
CHANGELOG
|
||||
=========
|
||||
|
||||
1.0.3 (2013-11-23)
|
||||
------------------
|
||||
|
||||
* Only set default timezone if the given $currentTime is not a DateTime instance ([#34](https://github.com/mtdowling/cron-expression/issues/34))
|
||||
* Fixes issue [#28](https://github.com/mtdowling/cron-expression/issues/28) where PHP increments of ranges were failing due to PHP casting hyphens to 0
|
||||
* Now supports expressions with any number of extra spaces, tabs, or newlines
|
||||
* Using static instead of self in `CronExpression::factory`
|
||||
- Composer is required to run the unit tests
|
@@ -13,7 +13,7 @@
|
||||
"php": ">=5.3.2"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "4.*"
|
||||
"phpunit/phpunit": "~4.0|~5.0"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-0": {
|
||||
|
@@ -1,17 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<phpunit bootstrap="./vendor/autoload.php"
|
||||
colors="true">
|
||||
|
||||
<testsuites>
|
||||
<testsuite name="Cron">
|
||||
<directory>./tests</directory>
|
||||
</testsuite>
|
||||
</testsuites>
|
||||
|
||||
<filter>
|
||||
<whitelist>
|
||||
<directory suffix=".php">./src/Cron</directory>
|
||||
</whitelist>
|
||||
</filter>
|
||||
|
||||
</phpunit>
|
@@ -101,4 +101,43 @@ abstract class AbstractField implements FieldInterface
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a range of values for the given cron expression
|
||||
*
|
||||
* @param string $expression The expression to evaluate
|
||||
* @param int $max Maximum offset for range
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getRangeForExpression($expression, $max)
|
||||
{
|
||||
$values = array();
|
||||
|
||||
if ($this->isRange($expression) || $this->isIncrementsOfRanges($expression)) {
|
||||
if (!$this->isIncrementsOfRanges($expression)) {
|
||||
list ($offset, $to) = explode('-', $expression);
|
||||
$stepSize = 1;
|
||||
}
|
||||
else {
|
||||
$range = array_map('trim', explode('/', $expression, 2));
|
||||
$stepSize = isset($range[1]) ? $range[1] : 0;
|
||||
$range = $range[0];
|
||||
$range = explode('-', $range, 2);
|
||||
$offset = $range[0];
|
||||
$to = isset($range[1]) ? $range[1] : $max;
|
||||
}
|
||||
$offset = $offset == '*' ? 0 : $offset;
|
||||
for ($i = $offset; $i <= $to; $i += $stepSize) {
|
||||
$values[] = $i;
|
||||
}
|
||||
sort($values);
|
||||
}
|
||||
else {
|
||||
$values = array($expression);
|
||||
}
|
||||
|
||||
return $values;
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -33,6 +33,11 @@ class CronExpression
|
||||
*/
|
||||
private $fieldFactory;
|
||||
|
||||
/**
|
||||
* @var int Max iteration count when searching for next run date
|
||||
*/
|
||||
private $maxIterationCount = 1000;
|
||||
|
||||
/**
|
||||
* @var array Order in which to test of cron parts
|
||||
*/
|
||||
@@ -72,6 +77,25 @@ class CronExpression
|
||||
return new static($expression, $fieldFactory ?: new FieldFactory());
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate a CronExpression.
|
||||
*
|
||||
* @param string $expression The CRON expression to validate.
|
||||
*
|
||||
* @return bool True if a valid CRON expression was passed. False if not.
|
||||
* @see Cron\CronExpression::factory
|
||||
*/
|
||||
public static function isValidExpression($expression)
|
||||
{
|
||||
try {
|
||||
self::factory($expression);
|
||||
} catch (\InvalidArgumentException $e) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse a CRON expression
|
||||
*
|
||||
@@ -121,7 +145,7 @@ class CronExpression
|
||||
{
|
||||
if (!$this->fieldFactory->getField($position)->validate($value)) {
|
||||
throw new \InvalidArgumentException(
|
||||
'Invalid CRON field value ' . $value . ' as position ' . $position
|
||||
'Invalid CRON field value ' . $value . ' at position ' . $position
|
||||
);
|
||||
}
|
||||
|
||||
@@ -130,6 +154,20 @@ class CronExpression
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set max iteration count for searching next run dates
|
||||
*
|
||||
* @param int $maxIterationCount Max iteration count when searching for next run date
|
||||
*
|
||||
* @return CronExpression
|
||||
*/
|
||||
public function setMaxIterationCount($maxIterationCount)
|
||||
{
|
||||
$this->maxIterationCount = $maxIterationCount;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a next run date relative to the current date or a specific date
|
||||
*
|
||||
@@ -183,7 +221,11 @@ class CronExpression
|
||||
{
|
||||
$matches = array();
|
||||
for ($i = 0; $i < max(0, $total); $i++) {
|
||||
$matches[] = $this->getRunDate($currentTime, $i, $invert, $allowCurrentDate);
|
||||
try {
|
||||
$matches[] = $this->getRunDate($currentTime, $i, $invert, $allowCurrentDate);
|
||||
} catch (\RuntimeException $e) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return $matches;
|
||||
@@ -239,6 +281,11 @@ class CronExpression
|
||||
$currentDate->setTimezone(new \DateTimeZone(date_default_timezone_get()));
|
||||
$currentDate = $currentDate->format('Y-m-d H:i');
|
||||
$currentTime = strtotime($currentDate);
|
||||
} elseif ($currentTime instanceof \DateTimeImmutable) {
|
||||
$currentDate = \DateTime::createFromFormat('U', $currentTime->format('U'));
|
||||
$currentDate->setTimezone(new \DateTimeZone(date_default_timezone_get()));
|
||||
$currentDate = $currentDate->format('Y-m-d H:i');
|
||||
$currentTime = strtotime($currentDate);
|
||||
} else {
|
||||
$currentTime = new \DateTime($currentTime);
|
||||
$currentTime->setTime($currentTime->format('H'), $currentTime->format('i'), 0);
|
||||
@@ -269,6 +316,9 @@ class CronExpression
|
||||
{
|
||||
if ($currentTime instanceof \DateTime) {
|
||||
$currentDate = clone $currentTime;
|
||||
} elseif ($currentTime instanceof \DateTimeImmutable) {
|
||||
$currentDate = \DateTime::createFromFormat('U', $currentTime->format('U'));
|
||||
$currentDate->setTimezone($currentTime->getTimezone());
|
||||
} else {
|
||||
$currentDate = new \DateTime($currentTime ?: 'now');
|
||||
$currentDate->setTimezone(new \DateTimeZone(date_default_timezone_get()));
|
||||
@@ -291,7 +341,7 @@ class CronExpression
|
||||
}
|
||||
|
||||
// Set a hard limit to bail on an impossible date
|
||||
for ($i = 0; $i < 1000; $i++) {
|
||||
for ($i = 0; $i < $this->maxIterationCount; $i++) {
|
||||
|
||||
foreach ($parts as $position => $part) {
|
||||
$satisfied = false;
|
||||
@@ -311,14 +361,14 @@ class CronExpression
|
||||
|
||||
// If the field is not satisfied, then start over
|
||||
if (!$satisfied) {
|
||||
$field->increment($nextRun, $invert);
|
||||
$field->increment($nextRun, $invert, $part);
|
||||
continue 2;
|
||||
}
|
||||
}
|
||||
|
||||
// Skip this match if needed
|
||||
if ((!$allowCurrentDate && $nextRun == $currentDate) || --$nth > -1) {
|
||||
$this->fieldFactory->getField(0)->increment($nextRun, $invert);
|
||||
$this->fieldFactory->getField(0)->increment($nextRun, $invert, isset($parts[0]) ? $parts[0] : null);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@@ -36,7 +36,10 @@ class DayOfWeekField extends AbstractField
|
||||
$tdate = clone $date;
|
||||
$tdate->setDate($currentYear, $currentMonth, $lastDayOfMonth);
|
||||
while ($tdate->format('w') != $weekday) {
|
||||
$tdate->setDate($currentYear, $currentMonth, --$lastDayOfMonth);
|
||||
$tdateClone = new \DateTime();
|
||||
$tdate = $tdateClone
|
||||
->setTimezone($tdate->getTimezone())
|
||||
->setDate($currentYear, $currentMonth, --$lastDayOfMonth);
|
||||
}
|
||||
|
||||
return $date->format('j') == $lastDayOfMonth;
|
||||
|
@@ -12,21 +12,51 @@ class HoursField extends AbstractField
|
||||
return $this->isSatisfied($date->format('H'), $value);
|
||||
}
|
||||
|
||||
public function increment(\DateTime $date, $invert = false)
|
||||
public function increment(\DateTime $date, $invert = false, $parts = null)
|
||||
{
|
||||
// Change timezone to UTC temporarily. This will
|
||||
// allow us to go back or forwards and hour even
|
||||
// if DST will be changed between the hours.
|
||||
$timezone = $date->getTimezone();
|
||||
$date->setTimezone(new \DateTimeZone('UTC'));
|
||||
if ($invert) {
|
||||
$date->modify('-1 hour');
|
||||
$date->setTime($date->format('H'), 59);
|
||||
} else {
|
||||
$date->modify('+1 hour');
|
||||
$date->setTime($date->format('H'), 0);
|
||||
if (is_null($parts) || $parts == '*') {
|
||||
$timezone = $date->getTimezone();
|
||||
$date->setTimezone(new \DateTimeZone('UTC'));
|
||||
if ($invert) {
|
||||
$date->modify('-1 hour');
|
||||
} else {
|
||||
$date->modify('+1 hour');
|
||||
}
|
||||
$date->setTimezone($timezone);
|
||||
|
||||
$date->setTime($date->format('H'), $invert ? 59 : 0);
|
||||
return $this;
|
||||
}
|
||||
|
||||
$parts = strpos($parts, ',') !== false ? explode(',', $parts) : array($parts);
|
||||
$hours = array();
|
||||
foreach ($parts as $part) {
|
||||
$hours = array_merge($hours, $this->getRangeForExpression($part, 23));
|
||||
}
|
||||
|
||||
$current_hour = $date->format('H');
|
||||
$position = $invert ? count($hours) - 1 : 0;
|
||||
if (count($hours) > 1) {
|
||||
for ($i = 0; $i < count($hours) - 1; $i++) {
|
||||
if ((!$invert && $current_hour >= $hours[$i] && $current_hour < $hours[$i + 1]) ||
|
||||
($invert && $current_hour > $hours[$i] && $current_hour <= $hours[$i + 1])) {
|
||||
$position = $invert ? $i : $i + 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$hour = $hours[$position];
|
||||
if ((!$invert && $date->format('H') >= $hour) || ($invert && $date->format('H') <= $hour)) {
|
||||
$date->modify(($invert ? '-' : '+') . '1 day');
|
||||
$date->setTime($invert ? 23 : 0, $invert ? 59 : 0);
|
||||
}
|
||||
else {
|
||||
$date->setTime($hour, $invert ? 59 : 0);
|
||||
}
|
||||
$date->setTimezone($timezone);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
@@ -12,12 +12,41 @@ class MinutesField extends AbstractField
|
||||
return $this->isSatisfied($date->format('i'), $value);
|
||||
}
|
||||
|
||||
public function increment(\DateTime $date, $invert = false)
|
||||
public function increment(\DateTime $date, $invert = false, $parts = null)
|
||||
{
|
||||
if ($invert) {
|
||||
$date->modify('-1 minute');
|
||||
} else {
|
||||
$date->modify('+1 minute');
|
||||
if (is_null($parts)) {
|
||||
if ($invert) {
|
||||
$date->modify('-1 minute');
|
||||
} else {
|
||||
$date->modify('+1 minute');
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
$parts = strpos($parts, ',') !== false ? explode(',', $parts) : array($parts);
|
||||
$minutes = array();
|
||||
foreach ($parts as $part) {
|
||||
$minutes = array_merge($minutes, $this->getRangeForExpression($part, 59));
|
||||
}
|
||||
|
||||
$current_minute = $date->format('i');
|
||||
$position = $invert ? count($minutes) - 1 : 0;
|
||||
if (count($minutes) > 1) {
|
||||
for ($i = 0; $i < count($minutes) - 1; $i++) {
|
||||
if ((!$invert && $current_minute >= $minutes[$i] && $current_minute < $minutes[$i + 1]) ||
|
||||
($invert && $current_minute > $minutes[$i] && $current_minute <= $minutes[$i + 1])) {
|
||||
$position = $invert ? $i : $i + 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ((!$invert && $current_minute >= $minutes[$position]) || ($invert && $current_minute <= $minutes[$position])) {
|
||||
$date->modify(($invert ? '-' : '+') . '1 hour');
|
||||
$date->setTime($date->format('H'), $invert ? 59 : 0);
|
||||
}
|
||||
else {
|
||||
$date->setTime($date->format('H'), $minutes[$position]);
|
||||
}
|
||||
|
||||
return $this;
|
||||
|
@@ -277,6 +277,27 @@ class CronExpressionTest extends \PHPUnit_Framework_TestCase
|
||||
), $cron->getMultipleRunDates(4, '2008-11-09 00:00:00', false, true));
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers Cron\CronExpression::getMultipleRunDates
|
||||
* @covers Cron\CronExpression::setMaxIterationCount
|
||||
*/
|
||||
public function testProvidesMultipleRunDatesForTheFarFuture() {
|
||||
// Fails with the default 1000 iteration limit
|
||||
$cron = CronExpression::factory('0 0 12 1 * */2');
|
||||
$cron->setMaxIterationCount(2000);
|
||||
$this->assertEquals(array(
|
||||
new DateTime('2016-01-12 00:00:00'),
|
||||
new DateTime('2018-01-12 00:00:00'),
|
||||
new DateTime('2020-01-12 00:00:00'),
|
||||
new DateTime('2022-01-12 00:00:00'),
|
||||
new DateTime('2024-01-12 00:00:00'),
|
||||
new DateTime('2026-01-12 00:00:00'),
|
||||
new DateTime('2028-01-12 00:00:00'),
|
||||
new DateTime('2030-01-12 00:00:00'),
|
||||
new DateTime('2032-01-12 00:00:00'),
|
||||
), $cron->getMultipleRunDates(9, '2015-04-28 00:00:00', false, true));
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers Cron\CronExpression
|
||||
*/
|
||||
@@ -373,4 +394,19 @@ class CronExpressionTest extends \PHPUnit_Framework_TestCase
|
||||
$cron->getPreviousRunDate($now);
|
||||
$this->assertEquals($strNow, $now->format(\DateTime::ISO8601));
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers Cron\CronExpression::__construct
|
||||
* @covers Cron\CronExpression::factory
|
||||
* @covers Cron\CronExpression::isValidExpression
|
||||
* @covers Cron\CronExpression::setExpression
|
||||
* @covers Cron\CronExpression::setPart
|
||||
*/
|
||||
public function testValidationWorks()
|
||||
{
|
||||
// Invalid. Only four values
|
||||
$this->assertFalse(CronExpression::isValidExpression('* * * 1'));
|
||||
// Valid
|
||||
$this->assertTrue(CronExpression::isValidExpression('* * * * 1'));
|
||||
}
|
||||
}
|
||||
|
@@ -35,4 +35,40 @@ class HoursFieldTest extends \PHPUnit_Framework_TestCase
|
||||
$f->increment($d, true);
|
||||
$this->assertEquals('2011-03-15 10:59:00', $d->format('Y-m-d H:i:s'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers Cron\HoursField::increment
|
||||
*/
|
||||
public function testIncrementsDateWithThirtyMinuteOffsetTimezone()
|
||||
{
|
||||
$tz = date_default_timezone_get();
|
||||
date_default_timezone_set('America/St_Johns');
|
||||
$d = new DateTime('2011-03-15 11:15:00');
|
||||
$f = new HoursField();
|
||||
$f->increment($d);
|
||||
$this->assertEquals('2011-03-15 12:00:00', $d->format('Y-m-d H:i:s'));
|
||||
|
||||
$d->setTime(11, 15, 0);
|
||||
$f->increment($d, true);
|
||||
$this->assertEquals('2011-03-15 10:59:00', $d->format('Y-m-d H:i:s'));
|
||||
date_default_timezone_set($tz);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers Cron\HoursField::increment
|
||||
*/
|
||||
public function testIncrementDateWithFifteenMinuteOffsetTimezone()
|
||||
{
|
||||
$tz = date_default_timezone_get();
|
||||
date_default_timezone_set('Asia/Kathmandu');
|
||||
$d = new DateTime('2011-03-15 11:15:00');
|
||||
$f = new HoursField();
|
||||
$f->increment($d);
|
||||
$this->assertEquals('2011-03-15 12:00:00', $d->format('Y-m-d H:i:s'));
|
||||
|
||||
$d->setTime(11, 15, 0);
|
||||
$f->increment($d, true);
|
||||
$this->assertEquals('2011-03-15 10:59:00', $d->format('Y-m-d H:i:s'));
|
||||
date_default_timezone_set($tz);
|
||||
}
|
||||
}
|
||||
|
@@ -37,6 +37,25 @@ class MonthFieldTest extends \PHPUnit_Framework_TestCase
|
||||
$this->assertEquals('2011-02-28 23:59:00', $d->format('Y-m-d H:i:s'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers Cron\MonthField::increment
|
||||
*/
|
||||
public function testIncrementsDateWithThirtyMinuteTimezone()
|
||||
{
|
||||
$tz = date_default_timezone_get();
|
||||
date_default_timezone_set('America/St_Johns');
|
||||
$d = new DateTime('2011-03-31 11:59:59');
|
||||
$f = new MonthField();
|
||||
$f->increment($d);
|
||||
$this->assertEquals('2011-04-01 00:00:00', $d->format('Y-m-d H:i:s'));
|
||||
|
||||
$d = new DateTime('2011-03-15 11:15:00');
|
||||
$f->increment($d, true);
|
||||
$this->assertEquals('2011-02-28 23:59:00', $d->format('Y-m-d H:i:s'));
|
||||
date_default_timezone_set($tz);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @covers Cron\MonthField::increment
|
||||
*/
|
||||
|
Reference in New Issue
Block a user