简体   繁体   English

PHP根据工作日函数计算日期

[英]PHP calculate a date based on function for working days

I am using this function (that I found on this forum) to calculate the number of working days between a range:我正在使用这个函数(我在这个论坛上找到的)来计算一个范围之间的工作日数:

<?php
//The function returns the no. of business days between two dates and it skips the holidays
function getWorkingDays($startDate,$endDate,$holidays){
// do strtotime calculations just once
$endDate = strtotime($endDate);
$startDate = strtotime($startDate);


//The total number of days between the two dates. We compute the no. of seconds and divide it to 60*60*24
//We add one to inlude both dates in the interval.
$days = ($endDate - $startDate) / 86400 + 1;

$no_full_weeks = floor($days / 7);
$no_remaining_days = fmod($days, 7);

//It will return 1 if it's Monday,.. ,7 for Sunday
$the_first_day_of_week = date("N", $startDate);
$the_last_day_of_week = date("N", $endDate);

//---->The two can be equal in leap years when february has 29 days, the equal sign is added here
//In the first case the whole interval is within a week, in the second case the interval falls in two weeks.
if ($the_first_day_of_week <= $the_last_day_of_week) {
    if ($the_first_day_of_week <= 6 && 6 <= $the_last_day_of_week) $no_remaining_days--;
    if ($the_first_day_of_week <= 7 && 7 <= $the_last_day_of_week) $no_remaining_days--;
}
else {
    // (edit by Tokes to fix an edge case where the start day was a Sunday
    // and the end day was NOT a Saturday)

    // the day of the week for start is later than the day of the week for end
    if ($the_first_day_of_week == 7) {
        // if the start date is a Sunday, then we definitely subtract 1 day
        $no_remaining_days--;

        if ($the_last_day_of_week == 6) {
            // if the end date is a Saturday, then we subtract another day
            $no_remaining_days--;
        }
    }
    else {
        // the start date was a Saturday (or earlier), and the end date was (Mon..Fri)
        // so we skip an entire weekend and subtract 2 days
        $no_remaining_days -= 2;
    }
}

//The no. of business days is: (number of weeks between the two dates) * (5 working days) + the remainder
//---->february in none leap years gave a remainder of 0 but still calculated weekends between first and last day, this is one way to fix it
$workingDays = $no_full_weeks * 5;
if ($no_remaining_days > 0 )
{
  $workingDays += $no_remaining_days;
}

//We subtract the holidays
foreach($holidays as $holiday){
    $time_stamp=strtotime($holiday);
    //If the holiday doesn't fall in weekend
    if ($startDate <= $time_stamp && $time_stamp <= $endDate && date("N",$time_stamp) != 6 && date("N",$time_stamp) != 7)
        $workingDays--;
}

return $workingDays;
}

//Example:

$holidays=array("2008-12-25","2008-12-26","2009-01-01");

echo getWorkingDays("$startdate","$enddate",$holidays)
?>

Now I'd like to extend this function a bit.现在我想稍微扩展一下这个功能。 I would like to generate what date it will be if I add X working days from the starting date.如果我从开始日期开始添加 X 个工作日,我想生成日期。 Say for example i have a variable that holds the value 20比如说我有一个变量,它的值是20

$workingdays = "20";

And the $startdate is 2012-06-01 i would like to make this function calculate that the startdate + 20 working days will be 2012-06-28. $startdate2012-06-01我想让这个函数计算出 startdate + 20 个工作日将是 2012-06-28。 Would this be possible?这可能吗?

I did a similar thing a while back using the below function.我不久前使用以下函数做了类似的事情。 the key here is skipping the weekends, you can extend this to skip holidays as well.这里的关键是跳过周末,您也可以将其扩展到跳过假期。

Example:例子:

Call the function - > addDays(strtotime($startDate), 20, $skipdays,$skipdates = array())调用函数 -> addDays(strtotime($startDate), 20, $skipdays,$skipdates = array())

 <?php
    function addDays($timestamp, $days, $skipdays = array("Saturday", "Sunday"), $skipdates = NULL) {
        // $skipdays: array (Monday-Sunday) eg. array("Saturday","Sunday")
        // $skipdates: array (YYYY-mm-dd) eg. array("2012-05-02","2015-08-01");
       //timestamp is strtotime of ur $startDate
        $i = 1;

        while ($days >= $i) {
            $timestamp = strtotime("+1 day", $timestamp);
            if ( (in_array(date("l", $timestamp), $skipdays)) || (in_array(date("Y-m-d", $timestamp), $skipdates)) )
            {
                $days++;
            }
            $i++;
        }

        return $timestamp;
        //return date("m/d/Y",$timestamp);
    }
    ?>

[Edit]: Just read an amazing article on nettuts, Hope this helps http://net.tutsplus.com/tutorials/php/dates-and-time-the-oop-way/ [编辑]:刚刚阅读了一篇关于 nettuts 的精彩文章,希望这有助于http://net.tutsplus.com/tutorials/php/dates-and-time-the-oop-way/

If someone's interested, I'm using this function to add X business days to a date.如果有人感兴趣,我正在使用此功能将 X 个工作日添加到日期。 The function takes in a timestamp and returns a timestamp.该函数接受一个时间戳并返回一个时间戳。 It's possible to specify the holidays via an array (if in the US, you can use usBankHolidays() ).可以通过数组指定假期(如果在美国,您可以使用usBankHolidays() )。

At the moment, it's assuming Saturday and Sunday are not business days but that can be changed easily.目前,假设周六和周日不是工作日,但可以轻松更改。

Code :代码

function addBusinessDays($date, $days, $holidays = array()) {
    $output = new DateTime();
    $output->setTimestamp($date);
    while ($days > 0) {
        $weekDay = $output->format('N');

        // Skip Saturday and Sunday
        if ($weekDay == 6 || $weekDay == 7) {
            $output = $output->add(new DateInterval('P1D'));
            continue;
        }

        // Skip holidays
        $strDate = $output->format('Y-m-d');
        foreach ($holidays as $s) {
            if ($s == $strDate) {
                $output = $output->add(new DateInterval('P1D'));
                continue 2;
            }
        }

        $days--;
        $output = $output->add(new DateInterval('P1D'));
    }
    return $output->getTimestamp();
}

function usBankHolidays($format = 'datesonly') {
    $output = array(
        array('2015-05-25', 'Memorial Day'),
        array('2015-07-03', 'Independence Day'),
        array('2015-09-07', 'Labor Day'),
        array('2015-10-12', 'Columbus Day'),
        array('2015-11-11', 'Veterans Day'),
        array('2015-11-26', 'Thanksgiving Day'),
        array('2015-12-25', 'Christmas Day'),
        array('2016-01-01', 'New Year Day'),
        array('2016-01-18', 'Martin Luther King Jr. Day'),
        array('2016-02-15', 'Presidents Day (Washingtons Birthday)'),
        array('2016-05-30', 'Memorial Day'),
        array('2016-07-04', 'Independence Day'),
        array('2016-09-05', 'Labor Day'),
        array('2016-10-10', 'Columbus Day'),
        array('2016-11-11', 'Veterans Day'),
        array('2016-11-24', 'Thanksgiving Day'),
        array('2016-12-25', 'Christmas Day'),
        array('2017-01-02', 'New Year Day'),
        array('2017-01-16', 'Martin Luther King Jr. Day'),
        array('2017-02-20', 'Presidents Day (Washingtons Birthday)'),
        array('2017-05-29', 'Memorial Day'),
        array('2017-07-04', 'Independence Day'),
        array('2017-09-04', 'Labor Day'),
        array('2017-10-09', 'Columbus Day'),
        array('2017-11-10', 'Veterans Day'),
        array('2017-11-23', 'Thanksgiving Day'),
        array('2017-12-25', 'Christmas Day'),
        array('2018-01-01', 'New Year Day'),
        array('2018-01-15', 'Martin Luther King Jr. Day'),
        array('2018-02-19', 'Presidents Day (Washingtons Birthday)'),
        array('2018-05-28', 'Memorial Day'),
        array('2018-07-04', 'Independence Day'),
        array('2018-09-03', 'Labor Day'),
        array('2018-10-08', 'Columbus Day'),
        array('2018-11-12', 'Veterans Day'),
        array('2018-11-22', 'Thanksgiving Day'),
        array('2018-12-25', 'Christmas Day'),
        array('2019-01-01', 'New Year Day'),
        array('2019-01-21', 'Martin Luther King Jr. Day'),
        array('2019-02-18', 'Presidents Day (Washingtons Birthday)'),
        array('2019-05-27', 'Memorial Day'),
        array('2019-07-04', 'Independence Day'),
        array('2019-09-02', 'Labor Day'),
        array('2019-10-14', 'Columbus Day'),
        array('2019-11-11', 'Veterans Day'),
        array('2019-11-28', 'Thanksgiving Day'),
        array('2019-12-25', 'Christmas Day'),
        array('2020-01-01', 'New Year Day'),
        array('2020-01-20', 'Martin Luther King Jr. Day'),
        array('2020-02-17', 'Presidents Day (Washingtons Birthday)'),
        array('2020-05-25', 'Memorial Day'),
        array('2020-07-03', 'Independence Day'),
        array('2020-09-07', 'Labor Day'),
        array('2020-10-12', 'Columbus Day'),
        array('2020-11-11', 'Veterans Day'),
        array('2020-11-26', 'Thanksgiving Day'),
        array('2020-12-25', 'Christmas Day '),
    );

    if ($format == 'datesonly') {
        $temp = array();
        foreach ($output as $item) {
            $temp[] = $item[0];
        }
        $output = $temp;
    }

    return $output;
}

Usage:用法:

$deliveryDate = addBusinessDays(time(), 7, usBankHolidays());

From @this.lau_ answer a rewrite simpler and more logical algorithm, with dynamic (fixed) holydays来自 @this.lau_ 的答案重写了一个更简单、更合乎逻辑的算法,带有动态(固定)的节日

public function addBusinessDays($date, $days) {

    $output = new DateTime();
    $output->setTimestamp($date);

    while ($days > 0) {

        $output = $output->add(new DateInterval('P1D'));
        $weekDay = $output->format('N');
        $strDate = $output->format('Y-m-d');

        // Skip Saturday and Sunday
        if ($weekDay == 6 || $weekDay == 7) {

            continue;

        }

        // Skip holidays
        $holidays = $this->_getHolidays();            

        foreach ($holidays as $holiday_date => $holiday_name) {

            if ($holiday_date == $strDate) {

                continue 2;

            }

        }

        $days--;

    }

    return $output->getTimestamp();

}



public function _getHolidays() {

    $feste = array(
        date("Y") . "-01-01" => "Capodanno", 
        date("Y") . "-01-06" => "Epifania", 
        date("Y") . "-04-25" => "Liberazione", 
        date("Y") . "-05-01" => "Festa Lavoratori", 
        date("Y") . "-06-02" => "Festa della Repubblica", 
        date("Y") . "-08-15" => "Ferragosto", 
        date("Y") . "-11-01" => "Tutti Santi", 
        date("Y") . "-12-08" => "Immacolata", 
        date("Y") . "-12-25" => "Natale", 
        date("Y") . "-12-26" => "St. Stefano"
    );

    return $feste;

}

Call the function with调用函数

$deliveryDate = addBusinessDays(time(), 7);

Using this.lau_ function , I was abble to reverse it, for subtraction dates, for use of a expiration date.使用 this.lau_ function ,我能够将其反转,用于减法日期,用于使用到期日期。 Hope this helps someone:希望这可以帮助某人:

function subBusinessDays( $date, $days, $holidays = array() ) {
            $output = new DateTime();
            $output->setTimestamp( $date );

            while ( $days > 0 ) {

                $output = $output->sub( new DateInterval( 'P1D' ) );

                // Skip holidays
                $strDate = $output->format( 'Y-m-d' );
                if ( in_array( $strDate, $holidays ) ) {
                    // Skip Saturday and Sunday
                    $output = $output->sub( new DateInterval( 'P1D' ) );
                    continue;
                }

                $weekDay = $output->format( 'N' );
                if ($weekDay <= 5 ) {
                    $days --;
                }

            }

            return $output->getTimestamp();
        }

I've got a better solution with only two parameters on the function.我有一个更好的解决方案,函数只有两个参数。

Just call the function只需调用函数

addDays($currentdate, $WordkingDatestoadd);

And then, use the below function然后,使用下面的函数

function addDays($timestamp, $days) {

$workingDays = [1, 2, 3, 4, 5]; # date format = N (1 = Monday, ...)
$holidayDays = ['*-12-25', '*-01-01']; # variable and fixed holidays

$timestamp = new DateTime($timestamp);
$days = $days;

for($i=1 ; $i <= $days; $i++){
    $timestamp = $timestamp->modify('+1 day');
    if ((!in_array($timestamp->format('N'), $workingDays)) && (!in_array($timestamp->format('*-m-d'), $holidayDays))){
        $i--;
    }
}

$timestamp = $timestamp->format('Y-m-d');
return $timestamp;
}

Here I use the HolidayAPI for the holiday's list dynamically.HolidayAPI is free to implement.在这里,我动态地使用 HolidayAPI 获取假期列表。HolidayAPI 可以免费实现。 I am Bangladeshi that's why I use the country code BD.我是孟加拉国人,这就是我使用国家代码 BD 的原因。 API link - https://holidayapi.com/v1/holidays?pretty&key=your_key&country=your_country_code&year=2020 API 链接 - https://holidayapi.com/v1/holidays?pretty&key=your_key&country=your_country_code&year=2020

// cURL start
$cURLConnection = curl_init();
curl_setopt($cURLConnection, CURLOPT_URL, 'your api');
curl_setopt($cURLConnection, CURLOPT_RETURNTRANSFER, true);
$phoneList = curl_exec($cURLConnection);
curl_close($cURLConnection);
$dateResponse = json_decode($phoneList);
// cURL end

$holidays = array(); //declear holidays array`enter code here`
for ($i=0;$i<count($dateResponse->holidays);$i++){
    $holidays[] = $dateResponse->holidays[$i]->date;  //inserting holidays in array from api
}

$startDate = "2020-02-26";  //insert value thats you prefer
$timestamp  = strtotime($startDate);  // convert date to time
$weekends = array("Friday", "Saturday");
$days = 0;  //initialization days counter

while (1){  //
    $timestamp = strtotime("+1 day", $timestamp); //day increment
    if ( (in_array(date("l", $timestamp), $weekends)) || (in_array(date("Y-m-d", $timestamp), $holidays)) ) //checking weekends and holidays
    {
        continue;
    }else{
        $days++;``
        if($days >= 5){  //interval - What will be the working days after 5 days
            echo date("Y-m-d", $timestamp); // print expected output
            break;
        }
    }
}

Input: 2020-02-26 Output: 2020-03-05输入:2020-02-26 输出:2020-03-05

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM