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 date函数参数详解
Nov 27 PHP
php笔记之:php函数range() round()和list()的使用说明
Apr 26 PHP
微信公众平台天气预报功能开发
Jul 06 PHP
php网站被挂木马后的修复方法总结
Nov 06 PHP
详解WordPress开发中get_header()获取头部函数的用法
Jan 08 PHP
php获取文件后缀的9种方法
Mar 22 PHP
PHP引用的调用方法分析
Apr 25 PHP
PHP微信开发之根据用户回复关键词\位置返回附近信息
Jun 24 PHP
PHP获取用户客户端真实IP的解决方案
Oct 10 PHP
Centos 6.5下PHP 5.3安装ffmpeg扩展的步骤详解
Mar 02 PHP
记Laravel调用Gin接口调用formData上传文件的实现方法
Dec 12 PHP
PHP中echo与print区别点整理
Mar 09 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
Protoss兵种介绍
2020/03/14 星际争霸
php for 循环语句使用方法详细说明
2010/05/09 PHP
PHP以指定字段为索引返回数据库所取的数据数组
2013/06/30 PHP
PHP的APC模块实现上传进度条
2015/10/27 PHP
php版微信数据统计接口用法示例
2016/10/12 PHP
php基于协程实现异步的方法分析
2019/07/17 PHP
js 颜色选择器(兼容firefox)
2009/03/05 Javascript
javascript学习笔记(五)正则表达式
2011/04/08 Javascript
js实现网站首页图片滚动显示
2013/02/04 Javascript
JS实现的另类手风琴效果网页内容切换代码
2015/09/08 Javascript
图文详解JavaScript的原型对象及原型链
2016/08/02 Javascript
jQuery元素属性操作实例(设置、获取及删除元素属性)
2016/09/08 Javascript
JavaScript实现鼠标滚轮控制页面图片切换功能示例
2017/10/14 Javascript
浅谈webpack-dev-server的配置和使用
2018/05/17 Javascript
vue-router中的hash和history两种模式的区别
2018/07/17 Javascript
Vue安装浏览器开发工具的步骤详解
2019/05/12 Javascript
vue中使用rem布局代码详解
2019/10/30 Javascript
微信小程序利用button控制条件标签的变量问题
2020/03/15 Javascript
.netcore+vue 实现压缩文件下载功能
2020/09/24 Javascript
如何用itertools解决无序排列组合的问题
2017/05/18 Python
使用Python实现微信提醒备忘录功能
2018/12/04 Python
Django stark组件使用及原理详解
2019/08/22 Python
python-序列解包(对可迭代元素的快速取值方法)
2019/08/24 Python
Python 中list ,set,dict的大规模查找效率对比详解
2019/10/11 Python
python模块常用用法实例详解
2019/10/17 Python
python爬取网易云音乐热歌榜实例代码
2020/08/07 Python
用ldap作为django后端用户登录验证的实现
2020/12/07 Python
利用CSS3实现圆角的outline效果的教程
2015/06/05 HTML / CSS
学生个人求职自荐信格式
2013/09/23 职场文书
导游实习生自荐书
2014/01/28 职场文书
单位消防安全责任书
2014/07/23 职场文书
2014年自愿离婚协议书
2014/10/10 职场文书
机关干部作风建设剖析材料
2014/10/23 职场文书
2016大学生优秀志愿者事迹材料
2016/02/25 职场文书
Redis基于Bitmap实现用户签到功能
2021/06/20 Redis
Docker官方工具docker-registry案例演示
2022/04/13 Servers