SoFunction
Updated on 2025-04-04

How to get the specific date of working days after the specified date in ThinkPHP

Ideas:

1. Get an array of all working days data in the query year
2. Get the index of the query start date on the working day
3. Calculate the date index to be queryed
4. Obtain the query date

/*Create date type record form*/

CREATE TABLE `tb_workday` (

`did` int(11) NOT NULL AUTO_INCREMENT,

`exact_date` varchar(32) NOT NULL COMMENT 'Specific date:Formatdate("Ymd");(20170205)',

`date_year` varchar(32) NOT NULL COMMENT 'Specific date:Formatdate("Y");(2017)',

`date_type` tinyint(2) NOT NULL COMMENT 'Date type: 0, working day; 1, special working day; 2, legal holiday',

PRIMARY KEY (`did`)

) ENGINE=InnoDB AUTO_INCREMENT=829 DEFAULT CHARSET=utf8 COMMENT='Working Days & Statutory Holiday Data for Each Year'
<?php

 

class work_days

{

 /**

  * Get the week

  * @param $date

  * @return mixed

  */

 function get_week($date)

 {

 //Captive date format
 $date_str = date('Y-m-d', strtotime($date));

 //Embroidered into an array
 $arr = explode("-", $date_str);

 //Argument assignment
 //Year
 $year = $arr[0];

 // Month, output 2-bit integer, not enough 2-bit right alignment
 $month = sprintf('%02d', $arr[1]);

 //Day, output 2-bit integer, not enough 2-bit right alignment
 $day = sprintf('%02d', $arr[2]);

 //The default assignment of hour, minute and second is 0;
 $hour = $minute = $second = 0;

 //Convert to timestamp
 $strap = mktime($hour, $minute, $second, $month, $day, $year);

 //Get the digital week day
 $number_wk = date("w", $strap);

 

 //Get the week corresponding to the number
 return $number_wk;

 

 //Customize the week array
 //$weekArr = array("Sunday", "Monday", "Tuesday", "Tuesday", "Friday", "Saturday");
 

 //Get the week corresponding to the number
 //return $weekArr[$number_wk];

 }

 

 

 /**

  * Get the date of each day within the specified date period

  * @param string $startdate Start date

  * @param string $enddate End date

  * @return array

  */

 function getDateFromRange($startdate, $enddate)

 {

 $stimestamp = strtotime($startdate);

 $etimestamp = strtotime($enddate);

 

 // Calculate how many days are there in the date period
 $days = ($etimestamp - $stimestamp) / 86400 + 1;

 

 // Save the date of each day
 $_list_date = array();

 for ($i = 0; $i < $days; $i++) {

 $_list_date[] = date('Y-m-d', $stimestamp + (86400 * $i));

 }

 return $_list_date;

 }

 

 function curl_post($url, $data = null)

 {

 $curl = curl_init();

 curl_setopt($curl, CURLOPT_URL, $url);

 curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, FALSE);

 curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, FALSE);

 if (!empty($data)) {

 curl_setopt($curl, CURLOPT_POST, 1);

 curl_setopt($curl, CURLOPT_POSTFIELDS, $data);

 }

 curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);

 $output = curl_exec($curl);

 curl_close($curl);

 return $output;

 }

 

 /**

  * Update the database specified year date data

  * @param $year

  * @return int

  */

 function updateDate($year)

 {

 $startDate = date('Y-m-d', strtotime($year . '-01-01'));

 $endDate = date('Y-m-d', strtotime('+1 year', strtotime($startDate)) - 86400);

 $_list_date = self::getDateFromRange($startDate, $endDate);

 

 $url = '/Tools/holiday';//Free API for searching by yourself
 

 $m = M('tb_workday');

 $count = 0;

 

 foreach ($_list_date as $k => $_date) {

 $_ret = 0;

 $_date = date('Ymd', strtotime($_date));

 $_post_data = array('date' => $_date);

 $_ret_curl = curl_post($url, $_post_data);

 $_ret_curl = json_decode($_ret_curl, true);

 

 //Working days
 if ($_ret_curl['data'] == 0) {

 $dateData['exact_date'] = $_date;

 $dateData['date_year'] = $year;

 $dateData['date_type'] = 0;

 $_ret = $m->add($dateData) ? 1 : 0;

 unset($dateData);

 

 

 //Working day to determine whether it is a weekend
 if (in_array(self::get_week($_date), array(0, 1))) {

  //Special working days
  $dateData['exact_date'] = $_date;

  $dateData['date_year'] = $year;

  $dateData['date_type'] = 1;

  $_ret = $m->add($dateData) ? 1 : 0;

  unset($dateData);

 }

 }

 

 //Legal holidays
 if ($_ret_curl['data'] == 2) {

 $dateData['exact_date'] = $_date;

 $dateData['date_year'] = $year;

 $dateData['date_type'] = 2;

 $_ret = $m->add($dateData) ? 1 : 0;

 unset($dateData);

 }

 

 //Off days (weekends) will not be processed for the time being
 /*if ($_ret_curl['data'] == 1) {

 

 }*/

 $_ret && $count++;

 unset($_date, $_post_data, $_ret_curl, $_ret);

 }

 return $count;

 }

 

 /**

  * Get all working days of that year (get from the database, if there is no data in the database, the data will be updated first)

  * @param string $year

  * @return array

  */

 private function getWorkDays($year)

 {

 $m = M('tb_workday');

 $map['date_year'] = $year;

 $map['date_type'] = 0;

 $DateArray = $m->field('exact_date')->where($map)->select();

 if (!empty($DateArray)) {

 $DateArray = array_column($DateArray, 'exact_date');

 return $DateArray;

 } else {

 //Update database working day data
 $ret = self::updateDate($year);

 if ($ret > 0) {

 return self::getWorkDays($year);

 } else {

 return false;

 }

 }

 }

 

 /**

  * Get the specific date of the Nth working day after the start date

  * @param $startdate string Calculate the start date and must include year, month and date information

  * @param $days int Number of days between

  * @return mixed successfully returns the corresponding date, and fails to return false

  */

 public function getNextWorkDate($startdate, $days)

 {

 $year = date('Y', strtotime($startdate));

 $startdate = date('Y-m-d', strtotime($startdate));

 

 $workDays = $this->getWorkDays($year);

 

 $search_key = array_search(date('Ymd', strtotime($startdate)), $workDays);

 

 if ($search_key === false) {//The query date is not working
 //Get the last working day before the query date
 $m = M('tb_workday');

 $map['date_year'] = $year;

 $map['date_type'] = 0;

 $map['DATE_FORMAT(`exact_date`,\'%Y-%m-%d\')'] = array('LT', $startdate);

 $_search_date = $m->where($map)->order('`exact_date` DESC')->getField('exact_date');

 $search_key = array_search($_search_date, $workDays);

 unset($m, $map, $_search_date);

 }

 

 $t_key = $search_key + $days;

 

 if ($t_key <= count($workDays) - 1) {

 return date('Y-m-d', strtotime($workDays[$t_key]));

 } else {

 //The query date has been crossed by the year
 $n_days = $days - (count($workDays) - 1 - $search_key);

 $next_year = $year + 1;

 return $this->getNextWorkDate($next_year . '-01-01', $n_days - 1);

 }

 }

}

 

 

$startdate = '2018-09-28';

$days = 5;

 

$class = new work_days();

$_date_workday = $class->getNextWorkDate($startdate, $days);

echo $_date_workday;//2018-10-10

You can test the above code locally, thank you for your support.