PHP实现两种排课方式

这篇文章主要介绍了PHP实现两种排课方式,第一种排课方式比较好理解,开始时间和结束时间,第二种比较复杂一些,有开始上课时间和结束上课时间和第几周,具体实现代码参考下本文

Posted in PHP onJune 26, 2021

两种排课方式:

固定每周的固定时间上课(例:共上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;
        }
 
        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日开始排课,每周一、周六上课:

PHP实现两种排课方式

(例子,只用来展示数据结构)排课结果为:

PHP实现两种排课方式


第二种排课方式稍微麻烦一点,简要代码如下:

/**
     * 生成日期列表
     *
     * @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实现两种排课方式

到此这篇关于PHP实现两种排课方式的文章就介绍到这了,更多相关PHP实现排课内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

PHP 相关文章推荐
PHP循环获取GET和POST值的代码
Apr 09 PHP
yii框架源码分析之创建controller代码
Jun 28 PHP
jQuery+php实现ajax文件即时上传的详解
Jun 17 PHP
thinkphp实现上一篇与下一篇的方法
Dec 08 PHP
PHP遍历数组的三种方法及效率对比分析
Feb 12 PHP
浅谈PHP接收POST数据方式
Jun 05 PHP
PHP可变函数学习小结
Nov 29 PHP
Zend Framework教程之Bootstrap类用法概述
Mar 14 PHP
PHP下的浮点运算不准的解决方法
Oct 27 PHP
PHP全功能无变形图片裁剪操作类与用法示例
Jan 10 PHP
PHP中localeconv()函数的用法
Mar 26 PHP
Laravel Eloquent ORM 实现查询表中指定的字段
Oct 17 PHP
Linux系统下安装PHP7.3版本
详细分析PHP7与PHP5区别
Jun 26 #PHP
laravel添加角色和模糊搜索功能的实现代码
一文搞懂php的垃圾回收机制
PHP中strval()函数实例用法
Jun 07 #PHP
使用php的mail()函数实现发送邮件功能
PHP实现rar解压读取扩展包小结
Jun 03 #PHP
You might like
thinkphp3.0 模板中函数的使用
2012/11/13 PHP
php文件上传的简单实例
2013/10/19 PHP
php字符串过滤与替换小结
2015/01/26 PHP
PHP使用递归生成文章树
2015/04/21 PHP
laravel 5.3中自定义加密服务的方案详解
2017/05/09 PHP
js调用AJAX时Get和post的乱码解决方法
2013/06/04 Javascript
JavaScript中的object转换函数toString()与valueOf()介绍
2014/12/31 Javascript
基于Node.js的JavaScript项目构建工具gulp的使用教程
2016/05/20 Javascript
使用jQuery实现WordPress中的Ctrl+Enter和@评论回复
2016/05/21 Javascript
jQuery提示插件qTip2用法分析(支持ajax及多种样式)
2016/06/08 Javascript
AngularJS延迟加载html template
2016/07/27 Javascript
js实现点击图片自动提交action的简单方法
2016/10/16 Javascript
jQuery树控件zTree使用方法详解(一)
2017/02/28 Javascript
jquery实现折叠菜单效果【推荐】
2017/03/08 Javascript
在iframe中使bootstrap的模态框在父页面弹出问题
2017/08/07 Javascript
浅谈关于angularJs中使用$.ajax的注意点
2017/08/12 Javascript
浅谈Express异步进化史
2017/09/09 Javascript
vue实现样式之间的切换及vue动态样式的实现方法
2017/12/19 Javascript
Nest.js 授权验证的方法示例
2021/02/22 Javascript
python 实现调用子文件下的模块方法
2018/12/07 Python
在python中使用with打开多个文件的方法
2019/01/07 Python
Python中的十大图像处理工具(小结)
2019/06/10 Python
django之自定义软删除Model的方法
2019/08/14 Python
django 做 migrate 时 表已存在的处理方法
2019/08/31 Python
python 上下文管理器及自定义原理解析
2019/11/19 Python
Python猫眼电影最近上映的电影票房信息
2020/09/18 Python
浅谈css3中的前缀
2016/07/20 HTML / CSS
迪卡侬印尼体育用品商店:Decathlon印尼
2020/03/11 全球购物
优质飞蝇钓和渔具:RiverBum
2020/05/10 全球购物
物流专业大学生求职信范文
2013/10/28 职场文书
《小山羊和小灰兔》教学反思
2014/02/19 职场文书
父母寄语大全
2014/04/12 职场文书
单位授权委托书范本
2014/09/26 职场文书
婚姻出轨保证书
2015/05/08 职场文书
vue如何批量引入组件、注册和使用详解
2021/05/12 Vue.js
pytorch 梯度NAN异常值的解决方案
2021/06/05 Python