= 5.3.0 * @author emptyhua@gmail.com * @link http://bluehua.org */ class CalUtil { public static function log($obj) { //调试开关.. if (true) return; if (is_string($obj)) echo $obj . "\n"; else var_dump($obj); } public static function DateTime($str) { return new DateTime($str); } private static function _rep_get_start(&$e_start, $z_start, $step) { while($e_start <= $z_start) { $e_start->modify('+' . $step); } $e_start->modify('-' . $step); } private static function _rep_add_valid_date(&$rt, $date, $start) { if ($date >= $start) { $rt[] = clone($date); } } /** * 找出一个重复事件在一段时间内会发生的日期 * * @param array $event * * $event = array( * 'start' => '2010-08-08 00:00:00', //事件第一次发生时的起始起时间 * 'end' => '2010-08-08 00:00:00', //事件第一次发生的结束时间 * 'interval' => 0, //每隔interval重复事件 * 'days_of_week' => array(),//每星期x,x,..重复 * 'days_of_month' => array(),//每月的x,x,..重复 * 'freq' => 'monthly'//重复类型,daily,weekly,monthly,yearly * ); * * @param int $start 时间段的开始 * @param int $end 时间段结束 * @return array 会发生重复事件的日期 */ public static function get_dates_of_repeat_event($event, $start, $end) { //函数返回结果声明 $result_days = array(); //第一次发生的起始时间 $event_start_t = self::DateTime($event['start']); $event_start_d = self::DateTime($event_start_t->format('Y-m-d')); //第一次发生的结束时间 $event_end_t = self::DateTime($event['end']); $event_end_d = self::DateTime($event_end_t->format('Y-m-d')); //时间段开始 $zone_start_d = self::DateTime($start); //时间段结束 $zone_end_d = self::DateTime($end); //如果第一次发生在时间段之后,返回空 if ($event_start_d > $zone_end_d) { self::log('zone_end_d lt than event_start_t'); return $result_days; } if ($zone_start_d < $event_start_d) { $zone_start_d = $event_start_d; } //如果重复事件设置了结束日期 if (!empty($event['util'])) { $event_util_d = self::DateTime($event['util']); //如果重复结束时间在时间段之前,返回空 if ($event_util_d < $zone_start_d) { self::log('event_util_d lt than zone_start_d'); return $result_days; } //如果结束日期在zone_end_d之前,则替代zone_end_d if ($event_util_d < $zone_end_d) { $zone_end_d = $event_util_d; } } //$_tmp = $zone_start_d->diff($event_start_d); //事件的重复频率,例如每两天,每三年,等.. $event_interval = isset($event['interval']) ? $event['interval'] : 1; //事件的重复间隔 $event_jump_step = null; //开始模拟重复事件的起始事件 $current_event_start_d = clone($zone_start_d); switch ($event['freq']) { case 'daily': $event_jump_step = $event_interval . ' days'; $_tmp = $current_event_start_d->diff($event_start_d); while($_tmp->days % $event_interval !== 0) { $current_event_start_d->modify('-1 days'); $_tmp = $current_event_start_d->diff($event_start_d); } break; case 'weekly': $event_jump_step = $event_interval . ' weeks'; $_tmp = $current_event_start_d->diff($event_start_d); while($_tmp->days % ($event_interval * 7) !== 0) { $current_event_start_d->modify('-1 days'); $_tmp = $current_event_start_d->diff($event_start_d); } self::log('increate start date:'); self::log($current_event_start_d); break; case 'monthly': $event_jump_step = $event_interval . ' months'; $_tmp = $current_event_start_d->format('Y-m-d'); $_tmp = explode('-', $_tmp); $_tmp2 = $event_start_d->format('d'); $current_event_start_d->setDate(intval($_tmp[0]), intval($_tmp[1]), intval($_tmp2)); $_tmp = $current_event_start_d->diff($event_start_d); while($_tmp->m % $event_interval !== 0) { $current_event_start_d->modify('-1 months'); $_tmp = $current_event_start_d->diff($event_start_d); } self::log('increate start date:'); self::log($current_event_start_d); break; case 'yearly': $event_jump_step = $event_interval . ' years'; $_tmp = $current_event_start_d->format('Y'); $_tmp2 = $event_start_d->format('m-d'); $_tmp2 = explode('-', $_tmp2); $current_event_start_d->setDate(intval($_tmp), intval($_tmp2[0]), intval($_tmp2[1])); $_tmp = $current_event_start_d->diff($event_start_d); while($_tmp->y % $event_interval !== 0) { $current_event_start_d->modify('-1 years'); $_tmp = $current_event_start_d->diff($event_start_d); } self::log('increate start date:'); self::log($current_event_start_d); break; } if (is_null($event_jump_step)) { self::log('invalid freq'); return $result_days; } $weekdays = $monthdays = null; //开始查找会发生重复事件的日期 while($current_event_start_d <= $zone_end_d) { switch($event['freq']) { case 'daily': case 'yearly': self::_rep_add_valid_date($result_days, $current_event_start_d, $zone_start_d); $current_event_start_d->modify('+' . $event_jump_step); break; case 'weekly': if (empty($event['days_of_week'])) { self::_rep_add_valid_date($result_days, $current_event_start_d, $zone_start_d); } else { if (is_null($weekdays)) { $weekdays = $event['days_of_week']; sort($weekdays); } $current_weekday = intval(date('w', $current_event_start_d->getTimestamp())); foreach($weekdays as $weekday) { $_offset = $weekday - $current_weekday; $_cd = clone($current_event_start_d); $_cd->modify(($_offset >= 0 ? '+' : '-') . $_offset . ' days'); self::_rep_add_valid_date($result_days, $_cd, $zone_start_d); } } $current_event_start_d->modify('+' . $event_jump_step); break; case 'monthly': if (empty($event['days_of_month'])) { self::_rep_add_valid_date($result_days, $current_event_start_d, $zone_start_d); } else { if (is_null($monthdays)) { $monthdays = $event['days_of_month']; sort($monthdays); } $current_monthday = intval(date('j', $current_event_start_d->getTimestamp())); foreach($monthdays as $monthday) { $_offset = $monthday - $current_monthday; $_cd = clone($current_event_start_d); $_cd->modify(($_offset >= 0 ? '+' : '-') . abs($_offset) . ' days'); self::_rep_add_valid_date($result_days, $_cd, $zone_start_d); } } $current_event_start_d->modify('+' . $event_jump_step); break; } } $start_time = $event_start_t->format('H:i:s'); $end_time = $event_end_t->format('H:i:s'); foreach($result_days as $i => $v) { $_prefix = $v->format('Y-m-d '); $result_days[$i] = array('start' => $_prefix . $start_time, 'end' => $_prefix . $end_time); } self::log('results:'); self::log($result_days); return $result_days; } } //测试代码 if (php_sapi_name() == 'cli' && realpath($_SERVER['SCRIPT_FILENAME']) == __FILE__) { //每天 //$rt = CalUtil::get_dates_of_repeat_event(array('start'=>'2010-08-08 08:00:00', 'end'=>'2010-08-08 09:00:00','freq'=>'daily'), '2111-08-30', '2111-09-10'); //每月 //$rt = CalUtil::get_dates_of_repeat_event(array('start'=>'2010-08-08 08:00:00', 'end'=>'2010-08-08 09:00:00','freq'=>'monthly','days_of_month'=>array(9,10)), '2010-10-1', '2010-11-30'); //$rt = CalUtil::get_dates_of_repeat_event(array('start'=>'2010-08-08 08:00:00', 'end'=>'2010-08-08 09:00:00','freq'=>'weekly','days_of_week'=>array(1,3,2)), '2010-08-30', '2010-09-30'); $rt = CalUtil::get_dates_of_repeat_event(array('start'=>'2010-08-08 08:00:00', 'end'=>'2010-08-08 09:00:00','freq'=>'yearly'), '2011-08-1', '2011-09-30'); //每两周的1,2,3 //$rt = CalUtil::get_dates_of_repeat_event(array('start'=>'2010-08-08 08:00:00', 'end'=>'2010-08-08 09:00:00','freq'=>'weekly','days_of_week'=>array(1,3,2), 'interval'=>2), '2010-08-30', '2010-09-30'); var_dump($rt); }