first commit
This commit is contained in:
commit
1218dd1517
12716 files changed
+989233
No files matched your search
@@ -0,0 +1,225 @@
|
||||
<?php
|
||||
namespace TYPO3\CMS\Scheduler\CronCommand;
|
||||
|
||||
/*
|
||||
* This file is part of the TYPO3 CMS project.
|
||||
*
|
||||
* It is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, either version 2
|
||||
* of the License, or any later version.
|
||||
*
|
||||
* For the full copyright and license information, please read the
|
||||
* LICENSE.txt file that was distributed with this source code.
|
||||
*
|
||||
* The TYPO3 project - inspiring people to share!
|
||||
*/
|
||||
|
||||
/**
|
||||
* This class provides calculations for the cron command format.
|
||||
*/
|
||||
class CronCommand
|
||||
{
|
||||
/**
|
||||
* Normalized sections of the cron command.
|
||||
* Allowed are comma separated lists of integers and the character '*'
|
||||
*
|
||||
* field lower and upper bound
|
||||
* ----- --------------
|
||||
* minute 0-59
|
||||
* hour 0-23
|
||||
* day of month 1-31
|
||||
* month 1-12
|
||||
* day of week 1-7
|
||||
*
|
||||
* @var array $cronCommandSections
|
||||
*/
|
||||
protected $cronCommandSections;
|
||||
|
||||
/**
|
||||
* Timestamp of next execution date.
|
||||
* This value starts with 'now + 1 minute' if not set externally
|
||||
* by unit tests. After a call to calculateNextValue() it holds the timestamp of
|
||||
* the next execution date which matches the cron command restrictions.
|
||||
*/
|
||||
protected $timestamp;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param string $cronCommand The cron command can hold any combination documented as valid
|
||||
* @param bool|int $timestamp Optional start time, used in unit tests
|
||||
*/
|
||||
public function __construct($cronCommand, $timestamp = false)
|
||||
{
|
||||
$cronCommand = NormalizeCommand::normalize($cronCommand);
|
||||
// Explode cron command to sections
|
||||
$this->cronCommandSections = \TYPO3\CMS\Core\Utility\GeneralUtility::trimExplode(' ', $cronCommand);
|
||||
// Initialize the values with the starting time
|
||||
// This takes care that the calculated time is always in the future
|
||||
if ($timestamp === false) {
|
||||
$timestamp = strtotime('+1 minute');
|
||||
} else {
|
||||
$timestamp += 60;
|
||||
}
|
||||
$this->timestamp = $this->roundTimestamp($timestamp);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the date of the next execution.
|
||||
*
|
||||
* @throws \RuntimeException
|
||||
*/
|
||||
public function calculateNextValue()
|
||||
{
|
||||
$newTimestamp = $this->getTimestamp();
|
||||
// Calculate next minute and hour field
|
||||
$loopCount = 0;
|
||||
while (true) {
|
||||
$loopCount++;
|
||||
// If there was no match within two days, cron command is invalid.
|
||||
// The second day is needed to catch the summertime leap in some countries.
|
||||
if ($loopCount > 2880) {
|
||||
throw new \RuntimeException('Unable to determine next execution timestamp: Hour and minute combination is invalid.', 1291494126);
|
||||
}
|
||||
if ($this->minuteAndHourMatchesCronCommand($newTimestamp)) {
|
||||
break;
|
||||
}
|
||||
$newTimestamp += 60;
|
||||
}
|
||||
$loopCount = 0;
|
||||
while (true) {
|
||||
$loopCount++;
|
||||
// A date must match within the next 4 years, this high number makes
|
||||
// sure leap year cron command configuration are caught.
|
||||
// If the loop runs longer than that, the cron command is invalid.
|
||||
if ($loopCount > 1464) {
|
||||
throw new \RuntimeException('Unable to determine next execution timestamp: Day of month, month and day of week combination is invalid.', 1291501280);
|
||||
}
|
||||
if ($this->dayMatchesCronCommand($newTimestamp)) {
|
||||
break;
|
||||
}
|
||||
$newTimestamp += $this->numberOfSecondsInDay($newTimestamp);
|
||||
}
|
||||
$this->timestamp = $newTimestamp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get next timestamp
|
||||
*
|
||||
* @return int Unix timestamp
|
||||
*/
|
||||
public function getTimestamp()
|
||||
{
|
||||
return $this->timestamp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get cron command sections. Array of strings, each containing either
|
||||
* a list of comma separated integers or *
|
||||
*
|
||||
* @return array command sections:
|
||||
* @internal
|
||||
*/
|
||||
public function getCronCommandSections()
|
||||
{
|
||||
return $this->cronCommandSections;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if current timestamp matches minute and hour cron command restriction.
|
||||
*
|
||||
* @param int $timestamp to test
|
||||
* @return bool TRUE if cron command conditions are met
|
||||
*/
|
||||
protected function minuteAndHourMatchesCronCommand($timestamp)
|
||||
{
|
||||
$minute = (int)date('i', $timestamp);
|
||||
$hour = (int)date('G', $timestamp);
|
||||
$commandMatch = false;
|
||||
if ($this->isInCommandList($this->cronCommandSections[0], $minute) && $this->isInCommandList($this->cronCommandSections[1], $hour)) {
|
||||
$commandMatch = true;
|
||||
}
|
||||
return $commandMatch;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if current timestamp matches day of month, month and day of week
|
||||
* cron command restriction
|
||||
*
|
||||
* @param int $timestamp to test
|
||||
* @return bool TRUE if cron command conditions are met
|
||||
*/
|
||||
protected function dayMatchesCronCommand($timestamp)
|
||||
{
|
||||
$dayOfMonth = date('j', $timestamp);
|
||||
$month = date('n', $timestamp);
|
||||
$dayOfWeek = date('N', $timestamp);
|
||||
$isInDayOfMonth = $this->isInCommandList($this->cronCommandSections[2], $dayOfMonth);
|
||||
$isInMonth = $this->isInCommandList($this->cronCommandSections[3], $month);
|
||||
$isInDayOfWeek = $this->isInCommandList($this->cronCommandSections[4], $dayOfWeek);
|
||||
// Quote from vixiecron:
|
||||
// Note: The day of a command's execution can be specified by two fields — day of month, and day of week.
|
||||
// If both fields are restricted (i.e., aren't *), the command will be run when either field
|
||||
// matches the current time. For example, `30 4 1,15 * 5' would cause
|
||||
// a command to be run at 4:30 am on the 1st and 15th of each month, plus every Friday.
|
||||
$isDayOfMonthRestricted = (string)$this->cronCommandSections[2] !== '*';
|
||||
$isDayOfWeekRestricted = (string)$this->cronCommandSections[4] !== '*';
|
||||
$commandMatch = false;
|
||||
if ($isInMonth) {
|
||||
if ($isInDayOfMonth && $isDayOfMonthRestricted || $isInDayOfWeek && $isDayOfWeekRestricted || $isInDayOfMonth && !$isDayOfMonthRestricted && $isInDayOfWeek && !$isDayOfWeekRestricted) {
|
||||
$commandMatch = true;
|
||||
}
|
||||
}
|
||||
return $commandMatch;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if a given number validates a cron command section. The given cron
|
||||
* command must be a 'normalized' list with only comma separated integers or '*'
|
||||
*
|
||||
* @param string $commandExpression: cron command
|
||||
* @param int $numberToMatch: number to look up
|
||||
* @return bool TRUE if number is in list
|
||||
*/
|
||||
protected function isInCommandList($commandExpression, $numberToMatch)
|
||||
{
|
||||
if ((string)$commandExpression === '*') {
|
||||
$inList = true;
|
||||
} else {
|
||||
$inList = \TYPO3\CMS\Core\Utility\GeneralUtility::inList($commandExpression, $numberToMatch);
|
||||
}
|
||||
return $inList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to calculate number of seconds in a day.
|
||||
*
|
||||
* This is not always 86400 (60*60*24) and depends on the timezone:
|
||||
* Some countries like Germany have a summertime / wintertime switch,
|
||||
* on every last sunday in march clocks are forwarded by one hour (set from 2:00 to 3:00),
|
||||
* and on last sunday of october they are set back one hour (from 3:00 to 2:00).
|
||||
* This shortens and lengthens the length of a day by one hour.
|
||||
*
|
||||
* @param int $timestamp Unix timestamp
|
||||
* @return int Number of seconds of day
|
||||
*/
|
||||
protected function numberOfSecondsInDay($timestamp)
|
||||
{
|
||||
$now = mktime(0, 0, 0, date('n', $timestamp), date('j', $timestamp), date('Y', $timestamp));
|
||||
// Make sure to be in next day, even if day has 25 hours
|
||||
$nextDay = $now + 60 * 60 * 25;
|
||||
$nextDay = mktime(0, 0, 0, date('n', $nextDay), date('j', $nextDay), date('Y', $nextDay));
|
||||
return $nextDay - $now;
|
||||
}
|
||||
|
||||
/**
|
||||
* Round a timestamp down to full minute.
|
||||
*
|
||||
* @param int $timestamp Unix timestamp
|
||||
* @return int Rounded timestamp
|
||||
*/
|
||||
protected function roundTimestamp($timestamp)
|
||||
{
|
||||
return mktime(date('H', $timestamp), date('i', $timestamp), 0, date('n', $timestamp), date('j', $timestamp), date('Y', $timestamp));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,364 @@
|
||||
<?php
|
||||
namespace TYPO3\CMS\Scheduler\CronCommand;
|
||||
|
||||
/*
|
||||
* This file is part of the TYPO3 CMS project.
|
||||
*
|
||||
* It is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, either version 2
|
||||
* of the License, or any later version.
|
||||
*
|
||||
* For the full copyright and license information, please read the
|
||||
* LICENSE.txt file that was distributed with this source code.
|
||||
*
|
||||
* The TYPO3 project - inspiring people to share!
|
||||
*/
|
||||
|
||||
use TYPO3\CMS\Core\Utility\MathUtility;
|
||||
|
||||
/**
|
||||
* Validate and normalize a cron command.
|
||||
*
|
||||
* Special fields like three letter weekdays, ranges and steps are substituted
|
||||
* to a comma separated list of integers. Example:
|
||||
* '2-4 10-40/10 * mar * fri' will be normalized to '2,4 10,20,30,40 * * 3 1,2'
|
||||
*/
|
||||
class NormalizeCommand
|
||||
{
|
||||
/**
|
||||
* Main API method: Get the cron command and normalize it.
|
||||
*
|
||||
* If no exception is thrown, the resulting cron command is validated
|
||||
* and consists of five whitespace separated fields, which are either
|
||||
* the letter '*' or a sorted, unique comma separated list of integers.
|
||||
*
|
||||
* @throws \InvalidArgumentException cron command is invalid or out of bounds
|
||||
* @param string $cronCommand The cron command to normalize
|
||||
* @return string Normalized cron command
|
||||
*/
|
||||
public static function normalize($cronCommand)
|
||||
{
|
||||
$cronCommand = trim($cronCommand);
|
||||
$cronCommand = self::convertKeywordsToCronCommand($cronCommand);
|
||||
$cronCommand = self::normalizeFields($cronCommand);
|
||||
return $cronCommand;
|
||||
}
|
||||
|
||||
/**
|
||||
* Accept special cron command keywords and convert to standard cron syntax.
|
||||
* Allowed keywords: @yearly, @annually, @monthly, @weekly, @daily, @midnight, @hourly
|
||||
*
|
||||
* @param string $cronCommand Cron command
|
||||
* @return string Normalized cron command if keyword was found, else unchanged cron command
|
||||
*/
|
||||
protected static function convertKeywordsToCronCommand($cronCommand)
|
||||
{
|
||||
switch ($cronCommand) {
|
||||
case '@yearly':
|
||||
case '@annually':
|
||||
$cronCommand = '0 0 1 1 *';
|
||||
break;
|
||||
case '@monthly':
|
||||
$cronCommand = '0 0 1 * *';
|
||||
break;
|
||||
case '@weekly':
|
||||
$cronCommand = '0 0 * * 0';
|
||||
break;
|
||||
case '@daily':
|
||||
|
||||
case '@midnight':
|
||||
$cronCommand = '0 0 * * *';
|
||||
break;
|
||||
case '@hourly':
|
||||
$cronCommand = '0 * * * *';
|
||||
break;
|
||||
}
|
||||
return $cronCommand;
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalize cron command field to list of integers or *
|
||||
*
|
||||
* @param string $cronCommand cron command
|
||||
* @return string Normalized cron command
|
||||
*/
|
||||
protected static function normalizeFields($cronCommand)
|
||||
{
|
||||
$fieldArray = self::splitFields($cronCommand);
|
||||
$fieldArray[0] = self::normalizeIntegerField($fieldArray[0], 0, 59);
|
||||
$fieldArray[1] = self::normalizeIntegerField($fieldArray[1], 0, 23);
|
||||
$fieldArray[2] = self::normalizeIntegerField($fieldArray[2], 1, 31);
|
||||
$fieldArray[3] = self::normalizeMonthAndWeekdayField($fieldArray[3], true);
|
||||
$fieldArray[4] = self::normalizeMonthAndWeekdayField($fieldArray[4], false);
|
||||
$normalizedCronCommand = implode(' ', $fieldArray);
|
||||
return $normalizedCronCommand;
|
||||
}
|
||||
|
||||
/**
|
||||
* Split a given cron command like '23 * * * *' to an array with five fields.
|
||||
*
|
||||
* @throws \InvalidArgumentException If splitted array does not contain five entries
|
||||
* @param string $cronCommand cron command
|
||||
* @return array
|
||||
*/
|
||||
protected static function splitFields($cronCommand)
|
||||
{
|
||||
$fields = explode(' ', $cronCommand);
|
||||
if (count($fields) !== 5) {
|
||||
throw new \InvalidArgumentException('Unable to split given cron command to five fields.', 1291227373);
|
||||
}
|
||||
return $fields;
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalize month field.
|
||||
*
|
||||
* @param string $expression Month field expression
|
||||
* @param bool $isMonthField TRUE if month field is handled, FALSE for weekday field
|
||||
* @return string Normalized expression
|
||||
*/
|
||||
protected static function normalizeMonthAndWeekdayField($expression, $isMonthField = true)
|
||||
{
|
||||
if ((string)$expression === '*') {
|
||||
$fieldValues = '*';
|
||||
} else {
|
||||
// Fragment expression by , / and - and substitute three letter code of month and weekday to numbers
|
||||
$listOfCommaValues = explode(',', $expression);
|
||||
$fieldArray = [];
|
||||
foreach ($listOfCommaValues as $listElement) {
|
||||
if (strpos($listElement, '/') !== false) {
|
||||
list($left, $right) = explode('/', $listElement);
|
||||
if (strpos($left, '-') !== false) {
|
||||
list($leftBound, $rightBound) = explode('-', $left);
|
||||
$leftBound = self::normalizeMonthAndWeekday($leftBound, $isMonthField);
|
||||
$rightBound = self::normalizeMonthAndWeekday($rightBound, $isMonthField);
|
||||
$left = $leftBound . '-' . $rightBound;
|
||||
} else {
|
||||
if ((string)$left !== '*') {
|
||||
$left = self::normalizeMonthAndWeekday($left, $isMonthField);
|
||||
}
|
||||
}
|
||||
$fieldArray[] = $left . '/' . $right;
|
||||
} elseif (strpos($listElement, '-') !== false) {
|
||||
list($left, $right) = explode('-', $listElement);
|
||||
$left = self::normalizeMonthAndWeekday($left, $isMonthField);
|
||||
$right = self::normalizeMonthAndWeekday($right, $isMonthField);
|
||||
$fieldArray[] = $left . '-' . $right;
|
||||
} else {
|
||||
$fieldArray[] = self::normalizeMonthAndWeekday($listElement, $isMonthField);
|
||||
}
|
||||
}
|
||||
$fieldValues = implode(',', $fieldArray);
|
||||
}
|
||||
return $isMonthField ? self::normalizeIntegerField($fieldValues, 1, 12) : self::normalizeIntegerField($fieldValues, 1, 7);
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalize integer field.
|
||||
*
|
||||
* @throws \InvalidArgumentException If field is invalid or out of bounds
|
||||
* @param string $expression Expression
|
||||
* @param int $lowerBound Lower limit of result list
|
||||
* @param int $upperBound Upper limit of result list
|
||||
* @return string Normalized expression
|
||||
*/
|
||||
protected static function normalizeIntegerField($expression, $lowerBound = 0, $upperBound = 59)
|
||||
{
|
||||
if ((string)$expression === '*') {
|
||||
$fieldValues = '*';
|
||||
} else {
|
||||
$listOfCommaValues = explode(',', $expression);
|
||||
$fieldArray = [];
|
||||
foreach ($listOfCommaValues as $listElement) {
|
||||
if (strpos($listElement, '/') !== false) {
|
||||
list($left, $right) = explode('/', $listElement);
|
||||
if ((string)$left === '*') {
|
||||
$leftList = self::convertRangeToListOfValues($lowerBound . '-' . $upperBound);
|
||||
} else {
|
||||
$leftList = self::convertRangeToListOfValues($left);
|
||||
}
|
||||
$fieldArray[] = self::reduceListOfValuesByStepValue($leftList . '/' . $right);
|
||||
} elseif (strpos($listElement, '-') !== false) {
|
||||
$fieldArray[] = self::convertRangeToListOfValues($listElement);
|
||||
} elseif (MathUtility::canBeInterpretedAsInteger($listElement)) {
|
||||
$fieldArray[] = $listElement;
|
||||
} elseif (strlen($listElement) === 2 && $listElement[0] === '0') {
|
||||
$fieldArray[] = (int)$listElement;
|
||||
} else {
|
||||
throw new \InvalidArgumentException('Unable to normalize integer field.', 1291429389);
|
||||
}
|
||||
}
|
||||
$fieldValues = implode(',', $fieldArray);
|
||||
}
|
||||
if ((string)$fieldValues === '') {
|
||||
throw new \InvalidArgumentException('Unable to convert integer field to list of values: Result list empty.', 1291422012);
|
||||
}
|
||||
if ((string)$fieldValues !== '*') {
|
||||
$fieldList = explode(',', $fieldValues);
|
||||
sort($fieldList);
|
||||
$fieldList = array_unique($fieldList);
|
||||
if (current($fieldList) < $lowerBound) {
|
||||
throw new \InvalidArgumentException('Lowest element in list is smaller than allowed.', 1291470084);
|
||||
}
|
||||
if (end($fieldList) > $upperBound) {
|
||||
throw new \InvalidArgumentException('An element in the list is higher than allowed.', 1291470170);
|
||||
}
|
||||
$fieldValues = implode(',', $fieldList);
|
||||
}
|
||||
return (string)$fieldValues;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a range of integers to a list: 4-6 results in a string '4,5,6'
|
||||
*
|
||||
* @throws \InvalidArgumentException If range can not be converted to list
|
||||
* @param string $range Integer-integer
|
||||
* @return string
|
||||
*/
|
||||
protected static function convertRangeToListOfValues($range)
|
||||
{
|
||||
if ((string)$range === '') {
|
||||
throw new \InvalidArgumentException('Unable to convert range to list of values with empty string.', 1291234985);
|
||||
}
|
||||
$rangeArray = explode('-', $range);
|
||||
// Sanitize fields and cast to integer
|
||||
foreach ($rangeArray as $fieldNumber => $fieldValue) {
|
||||
if (!MathUtility::canBeInterpretedAsInteger($fieldValue)) {
|
||||
throw new \InvalidArgumentException('Unable to convert value to integer.', 1291237668);
|
||||
}
|
||||
$rangeArray[$fieldNumber] = (int)$fieldValue;
|
||||
}
|
||||
|
||||
$rangeArrayCount = count($rangeArray);
|
||||
if ($rangeArrayCount === 1) {
|
||||
$resultList = $rangeArray[0];
|
||||
} elseif ($rangeArrayCount === 2) {
|
||||
$left = $rangeArray[0];
|
||||
$right = $rangeArray[1];
|
||||
if ($left > $right) {
|
||||
throw new \InvalidArgumentException('Unable to convert range to list: Left integer must not be greater than right integer.', 1291237145);
|
||||
}
|
||||
$resultListArray = [];
|
||||
for ($i = $left; $i <= $right; $i++) {
|
||||
$resultListArray[] = $i;
|
||||
}
|
||||
$resultList = implode(',', $resultListArray);
|
||||
} else {
|
||||
throw new \InvalidArgumentException('Unable to convert range to list of values.', 1291234986);
|
||||
}
|
||||
return (string)$resultList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reduce a given list of values by step value.
|
||||
* Following a range with ``/<number>'' specifies skips of the number's value through the range.
|
||||
* 1-5/2 -> 1,3,5
|
||||
* 2-10/3 -> 2,5,8
|
||||
*
|
||||
* @throws \InvalidArgumentException if step value is invalid or if resulting list is empty
|
||||
* @param string $stepExpression Step value expression
|
||||
* @return string Comma separated list of valid values
|
||||
*/
|
||||
protected static function reduceListOfValuesByStepValue($stepExpression)
|
||||
{
|
||||
if ($stepExpression === '') {
|
||||
throw new \InvalidArgumentException('Unable to convert step values.', 1291234987);
|
||||
}
|
||||
$stepValuesAndStepArray = explode('/', $stepExpression);
|
||||
$stepValuesAndStepArrayCount = count($stepValuesAndStepArray);
|
||||
if ($stepValuesAndStepArrayCount < 1 || $stepValuesAndStepArrayCount > 2) {
|
||||
throw new \InvalidArgumentException('Unable to convert step values: Multiple slashes found.', 1291242168);
|
||||
}
|
||||
$left = $stepValuesAndStepArray[0] ?? '';
|
||||
$right = $stepValuesAndStepArray[1] ?? '';
|
||||
if ($left === '') {
|
||||
throw new \InvalidArgumentException('Unable to convert step values: Left part of / is empty.', 1291414955);
|
||||
}
|
||||
if ($right === '') {
|
||||
throw new \InvalidArgumentException('Unable to convert step values: Right part of / is empty.', 1291414956);
|
||||
}
|
||||
if (!MathUtility::canBeInterpretedAsInteger($right)) {
|
||||
throw new \InvalidArgumentException('Unable to convert step values: Right part must be a single integer.', 1291414957);
|
||||
}
|
||||
$right = (int)$right;
|
||||
$leftArray = explode(',', $left);
|
||||
$validValues = [];
|
||||
$currentStep = $right;
|
||||
foreach ($leftArray as $leftValue) {
|
||||
if (!MathUtility::canBeInterpretedAsInteger($leftValue)) {
|
||||
throw new \InvalidArgumentException('Unable to convert step values: Left part must be a single integer or comma separated list of integers.', 1291414958);
|
||||
}
|
||||
if ($currentStep === 0) {
|
||||
$currentStep = $right;
|
||||
}
|
||||
if ($currentStep === $right) {
|
||||
$validValues[] = (int)$leftValue;
|
||||
}
|
||||
$currentStep--;
|
||||
}
|
||||
if (empty($validValues)) {
|
||||
throw new \InvalidArgumentException('Unable to convert step values: Result value list is empty.', 1291414959);
|
||||
}
|
||||
return implode(',', $validValues);
|
||||
}
|
||||
|
||||
/**
|
||||
* Dispatcher method for normalizeMonth and normalizeWeekday
|
||||
*
|
||||
* @param string $expression Month or weekday to be normalized
|
||||
* @param bool $isMonth TRUE if a month is handled, FALSE for weekday
|
||||
* @return string normalized month or weekday
|
||||
*/
|
||||
protected static function normalizeMonthAndWeekday($expression, $isMonth = true)
|
||||
{
|
||||
$expression = $isMonth ? self::normalizeMonth($expression) : self::normalizeWeekday($expression);
|
||||
return (string)$expression;
|
||||
}
|
||||
|
||||
/**
|
||||
* Accept a string representation or integer number of a month like
|
||||
* 'jan', 'February', 01, ... and convert to normalized integer value 1 .. 12
|
||||
*
|
||||
* @throws \InvalidArgumentException If month string can not be converted to integer
|
||||
* @param string $month Month representation
|
||||
* @return int month integer representation between 1 and 12
|
||||
*/
|
||||
protected static function normalizeMonth($month)
|
||||
{
|
||||
$timestamp = strtotime('2010-' . $month . '-01');
|
||||
// timestamp must be >= 2010-01-01 and <= 2010-12-01
|
||||
if (!$timestamp || $timestamp < strtotime('2010-01-01') || $timestamp > strtotime('2010-12-01')) {
|
||||
throw new \InvalidArgumentException('Unable to convert given month name.', 1291083486);
|
||||
}
|
||||
return (int)date('n', $timestamp);
|
||||
}
|
||||
|
||||
/**
|
||||
* Accept a string representation or integer number of a weekday like
|
||||
* 'mon', 'Friday', 3, ... and convert to normalized integer value 1 .. 7
|
||||
*
|
||||
* @throws \InvalidArgumentException If weekday string can not be converted
|
||||
* @param string $weekday Weekday representation
|
||||
* @return int weekday integer representation between 1 and 7
|
||||
*/
|
||||
protected static function normalizeWeekday($weekday)
|
||||
{
|
||||
$normalizedWeekday = false;
|
||||
// 0 (sunday) -> 7
|
||||
if ((string)$weekday === '0') {
|
||||
$weekday = 7;
|
||||
}
|
||||
if ($weekday >= 1 && $weekday <= 7) {
|
||||
$normalizedWeekday = (int)$weekday;
|
||||
}
|
||||
if (!$normalizedWeekday) {
|
||||
// Convert string representation like 'sun' to integer
|
||||
$timestamp = strtotime('next ' . $weekday, mktime(0, 0, 0, 1, 1, 2010));
|
||||
if (!$timestamp || $timestamp < strtotime('2010-01-01') || $timestamp > strtotime('2010-01-08')) {
|
||||
throw new \InvalidArgumentException('Unable to convert given weekday name.', 1291163589);
|
||||
}
|
||||
$normalizedWeekday = (int)date('N', $timestamp);
|
||||
}
|
||||
return $normalizedWeekday;
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user