最近为了写日期计算器,真真把自己绕的晕晕乎乎的。要计算隔一年,隔几个月后第几个星期,星期几等等。不是给定一个日期来获取这个日期是一年中的第几天或对应星期几。
因此为了方便后期开发日程管理类的功能,波波特意把本次项目中日程计划管理相关功能页面记录一个完整的笔记。本篇仅记录日程计划中最核心的日期计算器。
源码:
- /*
- * Create time by Json
- * @param $start int|string 开始时间
- * @param $sched array 日期规则
- * @return function(obj) 计算方法
- */
- function create_time_from_json($start=null,$sched){
- if(is_null($start)) {$start = time();}else{$start = strtotime($start) >time()?strtotime($start):time();}
- switch ($sched['type']){
- case 'year':
- if($sched['cycle_type'] == 'week'){
- //{"type":"year","cycle_type":"week","gap":"1","month":"3","week":"3","weekday":"wednesday","begin_time":"10:00"}
- $format = function($sched,$start){
- $weeken = ['monday','tuesday','wednesday','thursday','friday','saturday','sunday'];
- $year = date('Y',strtotime("+".$sched['gap']."year",strtotime($start)));
- $week = get_weekinfo($year.'-'.$sched['month']);
- $datetime = $week[$sched['week']-1][array_search($sched['weekday'],$weeken)]." ".$sched['begin_time'].":00";
- return $datetime;
- };
- }
- if($sched['cycle_type'] == 'month'){
- //{"type":"year","cycle_type":"month","gap":"1","month":"3","day":"2","begin_time":"10:00"}
- $format = function($sched,$start){
- $year = date('Y',strtotime("+".$sched['gap']."year",strtotime($start)));
- $sched['month'] = strlen($sched['month'])<2?"0".$sched['month']:$sched['month'];
- $sched['day'] = strlen($sched['day'])<2?"0".$sched['day']:$sched['day'];
- $datetime = implode("-",[$year,$sched['month'],$sched['day']])." ".$sched['begin_time'].":00";
- return $datetime;
- };
- }
- break;
- case 'month':
- if($sched['cycle_type'] == 'week'){
- //{"type":"month","cycle_type":"week","gap":"1","week":"1","weekday":"wednesday","begin_time":"10:00"}
- $format = function($sched,$start){
- $weeken = ['monday','tuesday','wednesday','thursday','friday','saturday','sunday'];
- $ym = date('Y-m',strtotime("+".$sched['gap']."month",strtotime($start)));
- $week = get_weekinfo($ym);
- $datetime = $week[$sched['week']-1][array_search($sched['weekday'],$weeken)]." ".$sched['begin_time'].":00";
- return $datetime;
- };
- }
- if($sched['cycle_type'] == 'day'){
- //{"type":"month","cycle_type":"day","gap":"1","day":"4","begin_time":"10:00"}
- $format = function($sched,$start){
- $ym = date('Y-m',strtotime($start."+".$sched['gap']."month"));
- $sched['day'] = strlen($sched['day'])<2?"0".$sched['day']:$sched['day'];
- $datetime = $ym."-".$sched['day']." ".$sched['begin_time'].":00";
- return $datetime;
- };
- }
- break;
- case 'week':
- //{"type":"week","gap":"2","begin_time":"12:00","week":{"tuesday":1,"wednesday":1,"friday":1}}
- $format = function ($sched,$start){
- $weeken = ['monday','tuesday','wednesday','thursday','friday','saturday','sunday'];
- $ymd = date('Y-m-d',strtotime("+".$sched['gap']."week",strtotime($start)));
- $week = get_weekinfo(mb_substr($ymd,0,7));
- foreach ($week as $key=>$value){
- if(in_array($ymd,$value)){
- foreach ($sched['week'] as $k=>$v){
- $datetime[] = $value[array_search($k,$weeken)]." ".$sched['begin_time'];
- }
- }
- }
- return $datetime;
- };
- break;
- case 'hour':
- //传入start参数须带时间!!!!
- $format = function ($sched,$start){
- $datetime = date('Y-m-d H:i:s',strtotime("+".$sched['gap'].$sched['type'],strtotime($start)));
- return $datetime;
- };
- break;
- case 'day':
- $format = function ($sched,$start){
- $datetime = date('Y-m-d',strtotime("+".$sched['gap'].$sched['type'],strtotime($start)))." ".$sched['begin_time'].":00";
- return $datetime;
- };
- break;
- default:
- $format = function ($sched,$start){
- return "非法的字符串";
- };
- }
- return $format;
- }
- /*
- * 计算某一年某个月有几周
- * @param $month string 年月
- * @return array
- * @notify 严禁传入日!!!
- */
- function get_weekinfo($month){
- $weekinfo = [];
- $end_date = date('d',strtotime($month.' +1 month -1 day'));//计算当前月有多少天
- for ($i=1; $i <$end_date ; $i=$i+7) {
- $w = date('N',strtotime($month.'-'.$i));
- $weekinfo[] = array(date('Y-m-d',strtotime($month.'-'.$i.' -'.($w-1).' days')),date('Y-m-d',strtotime($month.'-'.$i.' +'.(7-$w).' days')));
- }
- //填充每一周中间的日期
- foreach($weekinfo as $key=>$value){
- for($i=1;$i<7;$i++){
- $weekinfo[$key][$i] = date('Y-m-d',strtotime($value[0].'+'.$i.' days'));
- }
- }
- return $weekinfo;
- }
要对上述功能进行测试可以使用如下代码进行逐一测试。
- public function test(){
- $json = '{"type":"year","cycle_type":"month","gap":"1","month":"3","day":"2","begin_time":"10:00"}';
- $start = "2021-02-07 16:41:00";
- $begin = "2021-02-01 00:00:00";
- $end = "2021-02-28 00:00:00";
- $data = array();
- $schedule = json_decode($json,true);
- $format = create_time_from_json($start,$schedule);//获取时间计算函数
- while(strtotime($begin)<strtotime($start) && strtotime($start) < strtotime($end)){
- $temp = $format($schedule,$start);
- if(is_array($temp)){
- foreach ($temp as $key=>$vo){
- array_push($data,$vo);
- }
- }else{
- array_push($data,$temp);
- }
- $start = end($data);
- }
- echo "<pre>";
- print_r($data);
- }
关于JSON字符串的解释:(关于解释可参考文章最上面的图)
①type:计划类型,
②cycle_tyle:循环类型,一部分日程计划下面有循环类型,一部分没有。主要看第一个type的单位大不大。比如按运行时长的循环单位已经是小时了,所以下面就没必要再划分间隔的分钟数等
③gap:间隔周期,字段一样,计划类型不同代表的意义不同。
④month/day:月份和日,这没什么好解释的
⑤week/weekday:第几周和周几。
特别提示:
1、在上述示例中返回的数据其实是一个计算日期的方法。根据存储的日程JSON数据,获得对应日程日期的计算方法,然后根据计划的开始时间和结束时间再获取计划内应该安排的日程日期。
2、上述方法获得的日期为字符串格式,不是时间戳。字符串与时间戳之间的转换相信难不倒任何一个PHPer
随后波波也会分享日程页面的HTML以及完整的存储过程,敬请期待。