我正在我自己的个人框架中设计一个任务调度程序,并试图避免不那么灵活的“运行每个n分钟/小时/天”的方法会更容易实现。我想做的是模仿 cron 调度。我有适当的函数来分割模式并计算下一个日期(一个月中的某一天)的下一个值)目前,但如果有比我正在做的事情更容易的事情,或者可能有更好的方法来做我想做的事情,我不想继续前进。
/**
* Takes pattern(s) for various time attributes and calculates the next time the task should run
*
* @param mixed $minute Pattern or value of minute: 0-59 or 15,45 or * or * /5 (every 5 minutes)
* @param mixed $hour Pattern or value of hour: 0-23 or 0,6,12 or * or * /2 (every 2 hours)
* @param mixed $date Pattern or value of date: 1-31 or 1,15 or * or * /5 (every 5 days)
* @param mixed $day Pattern or value of weekday: 0-7 or 0,1,7 or * or * /7 (every 7 days) - takes precedence over date
* @return string Timestamp of next run time
*/
public static function calcNextRun( $minute, $hour, $date, $day )
{
# Simplest first, if all * then we run every minute. Return timestamp for next whole minute
if ( $minute == '*' && $hour == '*' && $date == '*' && $day == '*' )
return mktime( date( "H" ), date( "i" ), 0 ) + 60; # Prettier than time() + 60, isn't that reason enough?
# Default to current values
$nextDate = date( "d" );
$nextMonth = date( "m" );
$nextYear = date( "Y" );
$nextDay = date( "N" );
$nextHour = date( "H" );
$nextMinute = date( "i" );
# Calculate month date to run on, using multiple dates in the presence of , or -
if( strstr( $date, ',' ) || strstr( $date, '-' ) )
{
# Variable to determine whether the date has been set or not
$dateSet = false;
# Determine if there's a range in thurr
$rangeExists = ( strstr( $date, '-' ) ) ? true : false ;
# Set up the $dates array, exploding if multiple values is present
$dates = array();
if ( strstr( $date, ',' ) )
$dates = explode( ',', $date );
else
$dates[] = $date;
# If we have a range(s) present then we expand them into full stuffs
foreach ( $dates as $key => $val )
if ( strstr( $val, '-' ) )
$dates = array_merge( $dates, self::expandRange( $val ) ); # Merge the expanded range into the $dates array
# Loop through the $dates array and remove any lingering ranges
foreach ( $dates as $key => $val )
if ( strstr( $val, '-' ) )
unset( $dates[ $key ] );
# Sort the array
sort( $dates );
# Determine the next lowest value
foreach( $dates as $val )
{
# If the value is higher than the maximum number of dates this month, lower it to that
if ( $val > date( "t" ) )
$val = date( "t" );
# If $val is higher than today's date, we use that
if ( $val > date( "d" ) )
{
$nextDate = $val;
$dateSet = true;
break; # We're done, we have our value
}
}
# If the date has not been set, add one to the month and use the lowest value in the array
if ( !$dateSet )
{
# Increment the month. Maybe the year. Hurr hurr
if ( $nextMonth == 12 )
{
$nextMonth = 1;
$nextYear++;
}
else
$nextMonth++;
# Set the next day to the lowest value in the array
$nextDate = $dates[0];
}
}
elseif ( strstr( $date, '/' ) ) # Every n days
{
$parts = explode( '/', $date );
$numDays = array_pop( $parts );
# Calculate the timestamp of n days from now
$nDayTime = time() + ( $numDays * 86400 ); # 86400 seconds in a day
# Update values of $nextVars
$nextDate = date( "d", $nDayTime );
$nextMonth = date( "m", $nDayTime );
$nextYear = date( "Y", $nDayTime );
$nextDay = date( "N", $nDayTime );
}
elseif ( $date == (int)$date )
{
if ( $date < date( "j" ) )
{
# Determine if the month pushes into the next year
if ( $nextMonth == 12 )
{
$nextMonth = 1;
$nextYear++;
}
else
$nextMonth++;
}
$nextDate = $date;
}
# Return the new timestamp!
return mktime( $nextHour, $nextMinute, 0, $nextMonth, $nextDate, $nextYear );
}
/**
* Takes a range and returns an array with all values belonging to that range
*
* @param string $range Two values split by a hyphen, ie: 1-5, 0-9, etc.
* @return array Array of values between the two parts of the range
*/
private static function expandRange( $range )
{
# Get the parts of the range
$range = explode( '-', $range );
# Sort just in case the range is handed to us backwards. <_<
sort( $range );
# Set up our return array
$returnArray = array();
# Populate the return array with all values between min and max
for($i=$range[0];$i<=$range[1];$i++)
$returnArray[] = $i;
return $returnArray;
}
我不介意使用 cron 使用的所有五个参数,但无论哪种方式,我都希望能够轻松计算与提供的模式匹配的下一个时间戳。
有人对实现这一目标有任何建议吗?我正在考虑创建一个函数,该函数将采用模式(1-7,10,15 或 */5 或 * 或其他)和当前 val(当前分钟、月份中的某一天等)并返回下一个值从匹配或高于当前值的模式中。