PHP实现两种排课⽅式
两种排课⽅式:
固定每周的固定时间上课(例:共上20节,每周六、周⽇早上8点-10点上课。假如今天周六凌晨1点,那么排课也需要从今天开始)总共上⼏个周,每周上课时间⽐较个性化(例:共上三周,第⼀周周⼀周⼆早上8点-10点上课;第⼆周周三周四下午8点-10点上课;第三周周⽇中午11点-12点上课。)
第⼀种排课⽐较好实现,简要代码如下:
/**
* ⽣成⽇期列表
*
* @param int $startDate 开始⽇期时间戳格式
* @param array $timeList 课时计划列表
[
{
"start_at": "09:09", //开课时间
"end_at": "10:09", //结束时间
"week_at": 1 //周⼏
},
{
"start_at": "12:09", //开课时间
"end_at": "13:09", //结束时间
"week_at": 1 //周⼏
},
{
"start_at": "09:09",
"end_at": "10:09",
"week_at": 5
}
]
* @param int $amount 课时计划数量
* @param int $skipHoliday 跳过节假⽇
*
* @return array
*/
public function generateDateList($startDate, $timeList, $amount, $skipHoliday = 0)
{
// 计算开始⽇期是周⼏
$startDateWeek = intval(date('N', $startDate));
//规范化课时数据 week_at 做key的三维数组
foreach ($timeList as $item) {
$weekAt = $item['week_at'];
array_splice($item, 0, 0, $weekAt);
$key = array_shift($item);
$weeksTime[$key][] = $item;
$item = null;
}
php实例计算unset($timeList);
if (empty($weeksTime)) {
$this->addError('课时计划数据为空');
return false;
}
//设置跳过假期,获取开始⽇期之后的节假⽇
if ($skipHoliday) {
$holiday = new Holiday();
$holidayData = $holiday->getHolidayList($startDate);
$holiday = null;
unset($holiday);
}
$nowTime = time();
$list = array();
for ($weekStartTime = $startDate, $count = 0; $count < $amount; $weekStartTime += 86400 * 7) {
//$currentWeek :周⼏
foreach ($weeksTime as $currentWeek => $weekTime) {
foreach ($weekTime as $time) {
//算出对应的⽇期时间戳
$currentDateTime = $weekStartTime + (($startDateWeek <= $currentWeek ? ($currentWeek - $startDateWeek) : (7 - $startDateWeek + $currentWeek)) * 86400);
//对应的⽇期 = 开始时间 + ((开始时间对应周 <= 数据对应的周⼏? (数据对应的周⼏ - 开始时间对应周) :(7 - 开始时间对应周 + 数据对应的周⼏)) * 86400)
//假期跳过排课
if ($skipHoliday && !empty($holidayData)) {
$startUnix = $currentDateTime + $time['start_at'] * 3600; //开始时间
$endUnix = $currentDateTime + $time['end_at'] * 3600; //结束时间
$skip = false;
//选择跳过节假⽇,且节假⽇与当前课程时间有重叠跳过
foreach ($holidayData as $item) {
if (($item['start_at'] < $endUnix && $item['end_at'] > $startUnix) || ($item['start_at'] === $startUnix && $item['end_at'] === $endUnix)) {
$skip = true;
continue;
}
}
if ($skip) {
continue;
}
}
$currentDate = date('Y/m/d', $currentDateTime);
$startAt = strtotime($currentDate . $time['start_at'] . ':00');
$endAt = strtotime($currentDate . $time['end_at'] . ':00');
if($startAt < $nowTime || $endAt < $nowTime){
$this->addError('上课时间不能⼩于当前时间');
return false;
}
$list[] = [
'date_at' => $currentDateTime, //⽇期
'week_at' => $currentWeek, //周⼏
'start_at' => $startAt,
'end_at' => $endAt
];
$count++;
if ($count >= $amount) {
break 3;
}
}
}
}
$weeksTime = null;
unset($weeksTime);
return $list;
}
(例⼦,只⽤来展⽰数据结构)假如总共5节课时,从6-25⽇开始排课,每周⼀、周六上课:
(例⼦,只⽤来展⽰数据结构)排课结果为:
第⼆种排课⽅式稍微⿇烦⼀点,简要代码如下:
/**
* ⽣成⽇期列表
*
* @param int $startDate 开始⽇期时间戳格式
* @param array $taskList 任务列表
[
{
"start_at": "09:09", //开始上课时间
"end_at": "10:09", //结束时间
"week_at": 1, //周⼏
"week_number": 1 //第⼏周
},
{
"start_at": "09:09",
"end_at": "10:09",
"week_at": 2,
"week_number": 1
},
{
"start_at": "09:09",
"end_at": "10:09",
"week_at": 1,
"week_number": 3
}
]
*
* @return array
*/
public function generateDateList($startDate, $taskList)
{
// 计算开始⽇期是周⼏
$startDateWeek = intval(date('N', $startDate));
$list = [];
$nowTime = time();
$weekSign = $week = 0;
foreach($taskList as $key => $task){
if($task['week_number'] > $weekSign && $task['week_number'] != $week){
$weekSign = $task['week_number'] - $week;
}
//计算每条数据对应的⽇期 $key == 0:确定第⼀周第⼀节课是在本周还是下⼀周
if($key == 0 || $task['week_number'] == $week){
if($task['week'] >= $startDateWeek){
$task['date_at'] = $startDate +
(($weekSign - 1) * 7 + ($task['week'] - $startDateWeek)) * 86400; }else{
$task['date_at'] = $startDate +
(($weekSign) * 7 - ($startDateWeek - $task['week'])) * 86400;
}
}else{
if($task['week'] > $startDateWeek){
$task['date_at'] = $startDate +
(($weekSign) * 7 + ($task['week'] - $startDateWeek)) * 86400;
}else{
$task['date_at'] = $startDate +
(($weekSign) * 7 - ($startDateWeek - $task['week'])) * 86400;
}
}
$startDateWeek = intval(date('N', $task['date_at']));
$week = $task['week_number'];
$startDate = $task['date_at'];
$dateAt = date('Y/m/d', $task['date_at']);
$startAt = strtotime($dateAt . '00:00:00');
if($task['start_at']){
$startAt = strtotime($dateAt . $task['start_at'] . ':00');
}
$endAt = strtotime($dateAt . '23:59:59');
if($task['end_at']){
$endAt = strtotime($dateAt . $task['end_at'] . ':00');
}
if($startAt < $nowTime || $endAt < $nowTime){
$this->addError('上课时间不能⼩于当前时间');
return false;
}
$task['start_at'] = $startAt;
$task['end_at'] = $endAt;
//⽣成课时数据
$list[] = [
'date_at' => $task['date_at'],
'week_at' => $task['week'],
'start_at' => $startAt,
'end_at' => $endAt
];
}
return $list;
}
(例⼦,只⽤来展⽰数据结构)排课数据:
(例⼦,只⽤来展⽰数据结构)排课结果:
到此这篇关于PHP实现两种排课⽅式的⽂章就介绍到这了,更多相关PHP实现排课内容请搜索以前的⽂章或继续浏览下⾯的相关⽂章希望⼤家以后多多⽀持!
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论