主要用到的函数是 strtotime()
strtotime('+1 Tuesday', $timestamp) 获取下周二, 从时间戳$timestamp开始计算, 如果$timestamp留空, 则从当天开始计算
strtotime('+1 month', $timestamp) 获取下个月的x号, 还是以$timestamp开始计算的
1 /**
2 * desc 获取每周X执行的所有日期
3 * @param string $start 开始日期, 2016-10-17
4 * @param string $end 结束日期, 2016-10-17
5 * @param int $weekDay 1~5
6 * @return array
7 */
8 public function getWeeklyBuyDate($start, $end, $weekDay)
9 {
10 //获取每周要执行的日期 例如: 2016-01-02
11 $start = empty($start) ? date('Y-m-d') : $start;
12 $startTime = strtotime($start);
13
14 $startDay = date('N', $startTime);
15 if ($startDay < $weekDay) {
16 $startTime = strtotime(self::$WORK_DAY[$weekDay]['en'], strtotime($start)); //本周x开始, 例如, 今天(周二)用户设置每周四执行, 那本周四就会开始执行
17 } else {
18 $startTime = strtotime('next '.self::$WORK_DAY[$weekDay]['en'], strtotime($start));//下一个周x开始, 今天(周二)用户设置每周一执行, 那应该是下周一开始执行
19 }
20
21 $endTime = strtotime($end);
22 $list = [];
23 for ($i=0;;$i++) {
24 $dayOfWeek = strtotime("+{$i} week", $startTime); //每周x
25 if ($dayOfWeek > $endTime) {
26 break;
27 }
28 $list[] = date('Y-m-d', $dayOfWeek);
29 }
30
31 return $this->getExedate($start, $end, $list);
32 }
33
34 /**
35 * desc 获取每月X号执行的所有日期
36 * @param string $start 开始日期, 2016-10-17
37 * @param string $end 结束日期, 2016-10-17
38 * @param int $monthDay 1~28
39 * @return array
40 */
41 public function getMonthlyBuyDate($start, $end, $monthDay)
42 {
43 $monthDay = str_pad($monthDay, 2, '0', STR_PAD_LEFT); //左边补零
44 $start = empty($start) ? date('Y-m-d') : $start;
45 $startTime = strtotime($start);
46 $startDay = substr($start, 8, 2);
47
48 if (strcmp($startDay, $monthDay) < 0) {
49 $startMonthDayTime = strtotime(date('Y-m-', strtotime($start)).$monthDay); //本月开始执行, 今天(例如,26号)用户设置每月28号执行, 那么本月就开始执行
50 } else {
51 $startMonthDayTime = strtotime(date('Y-m-', strtotime('+1 month', $startTime)).$monthDay); //从下个月开始
52 }
53 $endTime = strtotime($end);
54
55 $list = [];
56 for ($i=0;;$i++) {
57 $dayOfMonth = strtotime("+{$i} month", $startMonthDayTime);//每月x号
58 if ($dayOfMonth > $endTime) {
59 break;
60 }
61 $list[] = date('Y-m-d', $dayOfMonth);
62 }
63
64 return $this->getExedate($start, $end, $list);
65
66 }
67
68 /**
69 * desc 返回顺延后的执行日期列表
70 * @param string $start 开始日期, 2016-10-17
71 * @param string $end 结束日期, 2016-10-17
72 * @param array $planDate
73 * @return array
74 */
75 public function getExedate($start, $end, $planDate)
76 {
77 //获取所有交易日
78 $allTradeDate = $this->getTradeDate($start, $end);
79
80 //取最后一个交易日
81 $endTradeDate = end($allTradeDate); //返回格式: ['2016-11-01' => '2016-11-01', '2016-11-02' => '2016-11-02', ...], 有冗余,方便编程
82
83 $exeDate = []; //顺延后的执行日期
84 foreach ($planDate as $date) {
85 if (!empty($allTradeDate[$date])) {
86 $exeDate[$date] = $date;
87 } else { //没找到, 需要往后顺延到下一个交易日
88 $exeDate[$date] = '';
89
90 $endTradeTime = strtotime($endTradeDate);
91 $currentTime = strtotime($date);
92
93 for ($i=$currentTime; $i<=$endTradeTime; $i+=86400) {//一天一天往后顺延, 直到找到下一个交易日, 直到数据库存储的最后一个交易日
94 $tmpDate = date('Y-m-d', $i);
95 if (!empty($allTradeDate[$tmpDate])) { //找到就退出循环
96 $exeDate[$date] = $tmpDate;
97 break;
98 }
99 }
100 }
101 }
102
103 return $exeDate;
104 }
其中:
1 public static $WORK_DAY = [
2 1 => ['en' => 'Monday', 'cn' => '一'],
3 2 => ['en' => 'Tuesday', 'cn' => '二'],
4 3 => ['en' => 'Wednesday', 'cn' => '三'],
5 4 => ['en' => 'Thursday', 'cn' => '四'],
6 5 => ['en' => 'Friday', 'cn' => '五']
7 ];