คำนวณวันทำการ


103

ฉันต้องการวิธีการเพิ่ม "วันทำการ" ใน PHP เช่นวันศุกร์ 12/5 + 3 วันทำการ = วันพุธ 12/10

อย่างน้อยที่สุดฉันต้องใช้รหัสเพื่อทำความเข้าใจวันหยุดสุดสัปดาห์ แต่ควรคำนึงถึงวันหยุดของรัฐบาลกลางของสหรัฐอเมริกาด้วย ฉันแน่ใจว่าฉันสามารถหาวิธีแก้ปัญหาได้โดยใช้กำลังดุร้ายหากจำเป็น แต่ฉันหวังว่าจะมีแนวทางที่สง่างามกว่านี้ ทุกคน?

ขอบคุณ.


ฉันสร้างห้องสมุดที่ดีสำหรับสิ่งนั้น github.com/andrejsstepanovs/business-days-calculatorมีความเสถียรและพร้อมที่จะเข้าสู่การผลิต
wormhit

6
โอ้ฉันคิดว่าเราควรพูดถึงว่าในปัจจุบันเราสามารถใช้ฟังก์ชัน DateTime :: modified เพื่อเพิ่มวันธรรมดาได้ทันที: $ my_date = new \ DateTime (); $ my_date-> แก้ไข ("+ 7 วันทำงาน"); จะดำเนินการอย่างดูเหมือนไม่มี
mika

บล็อกรายละเอียด: goo.gl/YOsfPX
Suresh Kamrushi

คำตอบที่ง่ายกว่า / สะอาดกว่า: stackoverflow.com/questions/5532002/…
Dave

คำตอบ:


103

นี่คือฟังก์ชั่นจากความคิดเห็นของผู้ใช้ในหน้าฟังก์ชัน date () ในคู่มือ PHP เป็นการปรับปรุงฟังก์ชันก่อนหน้านี้ในความคิดเห็นที่เพิ่มการสนับสนุนสำหรับปีอธิกสุรทิน

ป้อนวันที่เริ่มต้นและวันที่สิ้นสุดพร้อมกับอาร์เรย์ของวันหยุดที่อาจอยู่ระหว่างนั้นและส่งคืนวันทำงานเป็นจำนวนเต็ม:

<?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("2008-12-22","2009-01-02",$holidays)
// => will return 7
?>

4
ฟังก์ชันนี้คาดว่าวันที่เริ่มต้นและวันที่สิ้นสุดจะเป็นอย่างไรหากคุณมีวันที่เริ่มต้นและคุณต้องการให้ผลลัพธ์เป็น x วันทำการนับจากวันที่กำหนด
mcgrailm

@mcgrailm: เป็นแนวคิดที่คล้ายกัน แต่คุณอาจต้องการเขียนฟังก์ชันที่สองเนื่องจากอาร์กิวเมนต์และค่าที่ส่งคืนจะถูกสลับกัน จะเป็นประมาณ ((X วัน% 5 วันต่อสัปดาห์) * 2 วันต่อสุดสัปดาห์) + X วัน + ความแตกต่างของวันในสัปดาห์ของวันเริ่มต้นและวันที่สิ้นสุด + วันหยุด)
flamingLogos

@mcgrailm: พบคำถามนี้คำตอบอาจชี้ให้คุณไปในทิศทางที่ถูกต้อง: stackoverflow.com/questions/2681787/… .
flamingLogos

1
มีข้อบกพร่องในฟังก์ชันนี้ จะเกิดอะไรขึ้นหากมีการเปลี่ยนแปลงเขตเวลาระหว่างวันที่เหล่านั้น? ตัวอย่างเช่น CEST: echo getWorkingDays ("2012-01-01", "2012-05-01", $ วันหยุด); จะไม่ให้คุณเป็นจำนวนเต็ม stackoverflow.com/questions/12490521/…
mnowotka

5
นั่นเป็นวิธีเก่าที่จะทำ ใช้คำตอบGlavićถ้าเป็นไปได้
Thomas Ruiz

90

รับจำนวนวันทำงานโดยไม่มีวันหยุดระหว่างสองวัน:

ใช้ตัวอย่าง:

echo number_of_working_days('2013-12-23', '2013-12-29');

เอาท์พุต:

3

ฟังก์ชัน:

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

    $from = new DateTime($from);
    $to = new DateTime($to);
    $to->modify('+1 day');
    $interval = new DateInterval('P1D');
    $periods = new DatePeriod($from, $interval, $to);

    $days = 0;
    foreach ($periods as $period) {
        if (!in_array($period->format('N'), $workingDays)) continue;
        if (in_array($period->format('Y-m-d'), $holidayDays)) continue;
        if (in_array($period->format('*-m-d'), $holidayDays)) continue;
        $days++;
    }
    return $days;
}

ฉันโหวตให้เพราะมันใช้งานได้และมีการปรับปรุงที่ดี :) แต่อย่างน้อยคุณควรพูดถึง @Suresh Kamrushi ที่โพสต์รหัสนี้เกือบทุกเดือนก่อนหน้านี้ :)
KOGI

หากวันทำงานเป็นวันจันทร์ถึงวันศุกร์เสมอคุณสามารถแทนที่อาร์เรย์ DateInterval และ workingdays สำหรับ$interval = DateInterval::createFromFormat('1 weekday');ฉันขอแนะนำให้ใช้$holidays = array_flip($holidays);ก่อน foreach และ if isset($holidays[$period->format('Y-m-d')]);เพื่อลดระยะเวลาในการประมวลผลที่จำเป็นต่อการวนซ้ำ แต่ขอแนะนำให้สร้างฟังก์ชันที่กำหนดเองสำหรับวันหยุดเพื่อให้สามารถประมวลผลวันหยุดสัมพัทธ์เช่นวันขอบคุณพระเจ้าlast thursday of novemberหรือวันแรงงานfirst monday of september
fyrye

3
สิ่งนี้สามารถขยายให้รวมถึง Good Friday (ซึ่งฉันจำได้ว่าเป็นวันศุกร์ก่อนวันอาทิตย์แรกหลังจากพระจันทร์เต็มดวงแรกหลังวันที่ 21 มีนาคม)
Damian Yerrick

ระวังโซนเวลาที่แตกต่างกัน ที่นี่กับยุโรป / เบอร์ลินสิ่งนี้จะไม่ทำงาน ฉันแค่ทำในการประทับเวลาตอนนี้ด้วยวันที่ ('N') และเพิ่ม 1 วันและเขตเวลาที่เป็นอิสระ
user3655829

12

มีอาร์กิวเมนต์สำหรับฟังก์ชันdate ()ที่น่าจะช่วยได้ หากคุณตรวจสอบวันที่ ("w") จะให้ตัวเลขสำหรับวันในสัปดาห์ตั้งแต่ 0 สำหรับวันอาทิตย์ถึง 6 สำหรับวันเสาร์ ดังนั้น .. อาจจะมีบางอย่างเช่น ..

$busDays = 3;
$day = date("w");
if( $day > 2 && $day <= 5 ) { /* if between Wed and Fri */
  $day += 2; /* add 2 more days for weekend */
}
$day += $busDays;

นี่เป็นเพียงตัวอย่างคร่าวๆของความเป็นไปได้อย่างหนึ่ง ..


11

การคำนวณวันหยุดไม่เป็นไปตามมาตรฐานในแต่ละรัฐ ฉันกำลังเขียนใบสมัครของธนาคารซึ่งฉันต้องการกฎเกณฑ์ทางธุรกิจที่ยาก แต่ก็ยังได้มาตรฐานคร่าวๆเท่านั้น

/**
 * National American Holidays
 * @param string $year
 * @return array
 */
public static function getNationalAmericanHolidays($year) {


    //  January 1 - New Year’s Day (Observed)
    //  Calc Last Monday in May - Memorial Day  strtotime("last Monday of May 2011");
    //  July 4 Independence Day
    //  First monday in september - Labor Day strtotime("first Monday of September 2011")
    //  November 11 - Veterans’ Day (Observed)
    //  Fourth Thursday in November Thanksgiving strtotime("fourth Thursday of November 2011");
    //  December 25 - Christmas Day        
    $bankHolidays = array(
          $year . "-01-01" // New Years
        , "". date("Y-m-d",strtotime("last Monday of May " . $year) ) // Memorial Day
        , $year . "-07-04" // Independence Day (corrected)
        , "". date("Y-m-d",strtotime("first Monday of September " . $year) ) // Labor Day
        , $year . "-11-11" // Veterans Day
        , "". date("Y-m-d",strtotime("fourth Thursday of November " . $year) ) // Thanksgiving
        , $year . "-12-25" // XMAS
        );

    return $bankHolidays;
}

1
วันประกาศอิสรภาพคือ $ ปี '- 07-04' (4 กรกฎาคม) ไม่ใช่ 4 มิถุนายน
เพียงผู้เดียว

วันหยุดที่ตรงกับวันหยุดสุดสัปดาห์จะถือเป็นวันก่อน (ถ้าเป็นวันเสาร์) หรือวันถัดจาก (ถ้าเป็นวันอาทิตย์) ฉันสามารถใช้อาร์เรย์ของคุณเพื่อดูวันที่สังเกตได้จริง ขอบคุณ.
BrookeAH

9
$startDate = new DateTime( '2013-04-01' );    //intialize start date
$endDate = new DateTime( '2013-04-30' );    //initialize end date
$holiday = array('2013-04-11','2013-04-25');  //this is assumed list of holiday
$interval = new DateInterval('P1D');    // set the interval as 1 day
$daterange = new DatePeriod($startDate, $interval ,$endDate);
foreach($daterange as $date){
if($date->format("N") <6 AND !in_array($date->format("Y-m-d"),$holiday))
$result[] = $date->format("Y-m-d");
}
echo "<pre>";print_r($result);

6

นี่คือฟังก์ชันสำหรับการเพิ่มวันธุรกิจให้เป็นวันที่

 function add_business_days($startdate,$buisnessdays,$holidays,$dateformat){
  $i=1;
  $dayx = strtotime($startdate);
  while($i < $buisnessdays){
   $day = date('N',$dayx);
   $date = date('Y-m-d',$dayx);
   if($day < 6 && !in_array($date,$holidays))$i++;
   $dayx = strtotime($date.' +1 day');
  }
  return date($dateformat,$dayx);
 }

 //Example
 date_default_timezone_set('Europe\London');
 $startdate = '2012-01-08';
 $holidays=array("2012-01-10");
 echo '<p>Start date: '.date('r',strtotime( $startdate));
 echo '<p>'.add_business_days($startdate,7,$holidays,'r');

โพสต์อื่นกล่าวถึง getWorkingDays (จากความคิดเห็นของ php.net และรวมไว้ที่นี่) แต่ฉันคิดว่ามันจะแตกถ้าคุณเริ่มในวันอาทิตย์และเสร็จสิ้นในวันทำงาน

ใช้สิ่งต่อไปนี้ (คุณจะต้องรวมฟังก์ชัน getWorkingDays จากโพสต์ก่อนหน้านี้)

 date_default_timezone_set('Europe\London');
 //Example:
 $holidays = array('2012-01-10');
 $startDate = '2012-01-08';
 $endDate = '2012-01-13';
 echo getWorkingDays( $startDate,$endDate,$holidays);

ให้ผลลัพธ์เป็น 5 ไม่ใช่ 4

Sun, 08 Jan 2012 00:00:00 +0000 weekend
Mon, 09 Jan 2012 00:00:00 +0000
Tue, 10 Jan 2012 00:00:00 +0000 holiday
Wed, 11 Jan 2012 00:00:00 +0000
Thu, 12 Jan 2012 00:00:00 +0000
Fri, 13 Jan 2012 00:00:00 +0000 

ฟังก์ชันต่อไปนี้ถูกใช้เพื่อสร้างข้างต้น

     function get_working_days($startDate,$endDate,$holidays){
      $debug = true;
      $work = 0;
      $nowork = 0;
      $dayx = strtotime($startDate);
      $endx = strtotime($endDate);
      if($debug){
       echo '<h1>get_working_days</h1>';
       echo 'startDate: '.date('r',strtotime( $startDate)).'<br>';
       echo 'endDate: '.date('r',strtotime( $endDate)).'<br>';
       var_dump($holidays);
       echo '<p>Go to work...';
      }
      while($dayx <= $endx){
       $day = date('N',$dayx);
       $date = date('Y-m-d',$dayx);
       if($debug)echo '<br />'.date('r',$dayx).' ';
       if($day > 5 || in_array($date,$holidays)){
        $nowork++;
     if($debug){
      if($day > 5)echo 'weekend';
      else echo 'holiday';
     }
       } else $work++;
       $dayx = strtotime($date.' +1 day');
      }
      if($debug){
      echo '<p>No work: '.$nowork.'<br>';
      echo 'Work: '.$work.'<br>';
      echo 'Work + no work: '.($nowork+$work).'<br>';
      echo 'All seconds / seconds in a day: '.floatval(strtotime($endDate)-strtotime($startDate))/floatval(24*60*60);
      }
      return $work;
     }

    date_default_timezone_set('Europe\London');
     //Example:
     $holidays=array("2012-01-10");
     $startDate = '2012-01-08';
     $endDate = '2012-01-13';
//broken
     echo getWorkingDays( $startDate,$endDate,$holidays);
//works
     echo get_working_days( $startDate,$endDate,$holidays);

นำในวันหยุด ...


3

คุณสามารถลองใช้ฟังก์ชันนี้ซึ่งง่ายกว่า

function getWorkingDays($startDate, $endDate)
{
    $begin = strtotime($startDate);
    $end   = strtotime($endDate);
    if ($begin > $end) {

        return 0;
    } else {
        $no_days  = 0;
        while ($begin <= $end) {
            $what_day = date("N", $begin);
            if (!in_array($what_day, [6,7]) ) // 6 and 7 are weekend
                $no_days++;
            $begin += 86400; // +1 day
        };

        return $no_days;
    }
}

2

ฟังก์ชันในการเพิ่มหรือลบวันทำการจากวันที่ที่กำหนดซึ่งไม่รวมถึงวันหยุด

function dateFromBusinessDays($days, $dateTime=null) {
  $dateTime = is_null($dateTime) ? time() : $dateTime;
  $_day = 0;
  $_direction = $days == 0 ? 0 : intval($days/abs($days));
  $_day_value = (60 * 60 * 24);

  while($_day !== $days) {
    $dateTime += $_direction * $_day_value;

    $_day_w = date("w", $dateTime);
    if ($_day_w > 0 && $_day_w < 6) {
      $_day += $_direction * 1; 
    }
  }

  return $dateTime;
}

ใช้แบบนั้น ...

echo date("m/d/Y", dateFromBusinessDays(-7));
echo date("m/d/Y", dateFromBusinessDays(3, time() + 3*60*60*24));

2

เวอร์ชันของฉันอิงตามผลงานของ @mcgrailm ... ปรับเปลี่ยนเนื่องจากต้องตรวจสอบรายงานภายใน 3 วันทำการและหากส่งในวันหยุดสุดสัปดาห์การนับจะเริ่มในวันจันทร์ถัดไป:

function business_days_add($start_date, $business_days, $holidays = array()) {
    $current_date = strtotime($start_date);
    $business_days = intval($business_days); // Decrement does not work on strings
    while ($business_days > 0) {
        if (date('N', $current_date) < 6 && !in_array(date('Y-m-d', $current_date), $holidays)) {
            $business_days--;
        }
        if ($business_days > 0) {
            $current_date = strtotime('+1 day', $current_date);
        }
    }
    return $current_date;
}

และหาข้อแตกต่างของวันที่สองวันในแง่ของวันทำการ:

function business_days_diff($start_date, $end_date, $holidays = array()) {
    $business_days = 0;
    $current_date = strtotime($start_date);
    $end_date = strtotime($end_date);
    while ($current_date <= $end_date) {
        if (date('N', $current_date) < 6 && !in_array(date('Y-m-d', $current_date), $holidays)) {
            $business_days++;
        }
        if ($current_date <= $end_date) {
            $current_date = strtotime('+1 day', $current_date);
        }
    }
    return $business_days;
}

โปรดทราบว่าทุกคนที่ใช้ 86400 หรือ 24 * 60 * 60 โปรดอย่า ... เวลาในการลืมของคุณจะเปลี่ยนไปจากเวลาฤดูหนาว / ฤดูร้อนโดยที่แต่ละวันไม่ใช่ 24 ชั่วโมง แม้ว่า strtotime จะช้าลงเล็กน้อย ('+ 1 วัน', $ timestamp) แต่ก็น่าเชื่อถือกว่ามาก


2

ความพยายามที่ดุร้ายในการตรวจจับเวลาทำงาน - วันจันทร์ถึงวันศุกร์ 8: 00-16: 00 น.:

if (date('N')<6 && date('G')>8 && date('G')<16) {
   // we have a working time (or check for holidays)
}

2

ด้านล่างนี้คือรหัสการทำงานเพื่อคำนวณวันทำการจากวันที่กำหนด

<?php
$holiday_date_array = array("2016-01-26", "2016-03-07", "2016-03-24", "2016-03-25", "2016-04-15", "2016-08-15", "2016-09-12", "2016-10-11", "2016-10-31");
$date_required = "2016-03-01";

function increase_date($date_required, $holiday_date_array=array(), $days = 15){
    if(!empty($date_required)){
        $counter_1=0;
        $incremented_date = '';
        for($i=1; $i <= $days; $i++){
            $date = strtotime("+$i day", strtotime($date_required));
            $day_name = date("D", $date);
            $incremented_date = date("Y-m-d", $date);
            if($day_name=='Sat'||$day_name=='Sun'|| in_array($incremented_date ,$holiday_date_array)==true){
                $counter_1+=1;
            }
        }
        if($counter_1 > 0){
            return increase_date($incremented_date, $holiday_date_array, $counter_1);
        }else{
            return $incremented_date;
        }
    }else{
        return 'invalid';
    }
}

echo increase_date($date_required, $holiday_date_array, 15);
?>

//output after adding 15 business working days in 2016-03-01 will be "2016-03-23"

2

นี่เป็นอีกวิธีหนึ่งที่ไม่มีการวนซ้ำในแต่ละวัน

$from = new DateTime($first_date);
$to = new DateTime($second_date);

$to->modify('+1 day');
$interval = $from->diff($to);
$days = $interval->format('%a');

$extra_days = fmod($days, 7);
$workdays = ( ( $days - $extra_days ) / 7 ) * 5;

$first_day = date('N', strtotime($first_date));
$last_day = date('N', strtotime("1 day", strtotime($second_date)));
$extra = 0;
if($first_day > $last_day) {
   if($first_day == 7) {
       $first_day = 6;
   }

   $extra = (6 - $first_day) + ($last_day - 1);
   if($extra < 0) {
       $extra = $extra * -1;
   }
}
if($last_day > $first_day) {
    $extra = $last_day - $first_day;
}
$days = $workdays + $extra

1

สำหรับวันหยุดให้สร้างอาร์เรย์ของวันในบางรูปแบบที่วันที่ () สามารถผลิตได้ ตัวอย่าง:

// I know, these aren't holidays
$holidays = array(
    'Jan 2',
    'Feb 3',
    'Mar 5',
    'Apr 7',
    // ...
);

จากนั้นใช้ฟังก์ชันin_array ()และdate ()เพื่อตรวจสอบว่าการประทับเวลาแสดงถึงวันหยุดหรือไม่:

$day_of_year = date('M j', $timestamp);
$is_holiday = in_array($day_of_year, $holidays);

1

ฉันมีความต้องการแบบเดียวกันนี้ฉันเริ่มต้นด้วยตัวอย่างแรกของกระสวยและลงเอยด้วยสิ่งนี้

  function add_business_days($startdate,$buisnessdays,$holidays=array(),$dateformat){
    $enddate = strtotime($startdate);
    $day = date('N',$enddate);
    while($buisnessdays > 1){
        $enddate = strtotime(date('Y-m-d',$enddate).' +1 day');
        $day = date('N',$enddate);
        if($day < 6 && !in_array($enddate,$holidays))$buisnessdays--;
    }
    return date($dateformat,$enddate);
  }

ใครบางคน


ขออภัย mcgrailm ของคุณใช้งานไม่ได้เลย .... มันไม่ได้คำนึงถึงว่าวันใน $ enddate ตรงกับวันหยุด ... มันเป็นเพียงความกังวลเกี่ยวกับวันหยุดในระหว่างการเพิ่มเว้นแต่ฉันจะพลาดอะไรบางอย่าง

@ ริชาร์ดฉันคิดว่าฉันเข้าใจสิ่งที่คุณพูด ไม่ตรวจสอบวันที่เริ่มต้นเพื่อดูว่าเป็นวันหยุดหรือวันหยุดสุดสัปดาห์ที่คำนวณวันทำการหลังจากวันที่เริ่มต้น หากคุณต้องการรวมวันที่เริ่มต้นในการตรวจสอบคุณสามารถใช้วันที่ +1 ได้
mcgrailm

ฉันคิดว่ามันขึ้นอยู่กับไวยากรณ์และสิ่งที่คุณพยายามจะบรรลุ ตัวอย่างเช่นฉันพยายามหาข้อสรุปเมื่อต้องตรวจสอบรายงาน แต่ถ้าส่งในวันหยุดสุดสัปดาห์และต้องดำเนินการให้เสร็จใน 3 ธุรกิจการนับจะเริ่มในวันจันทร์ (โดยไม่ใช่วันหยุด) ... ฉันได้โพสต์เวอร์ชันของฉันซึ่งทั้งสองตามรหัสของคุณ แต่ปรับแต่งเล็กน้อย
Craig Francis

มีประโยชน์มาก - สิ่งหนึ่งที่ฉันต้องเปลี่ยน!in_array($enddate,$holidays)เป็น!in_array(date('Y-m-d',$enddate),$holidays)ถ้าใช้อาร์เรย์วันหยุดที่ส่งผ่านเช่น Bobbins '- $holidays=array('2013-06-16','2013-07-12','2013-08-05');มิฉะนั้นคุณกำลังตรวจสอบอาร์เรย์ที่เต็มไปด้วยวันที่สำหรับการประทับเวลาซึ่งจะส่งคืนเท็จเสมอ
McNab

1

ตัวแปร 1:

<?php
/*
 * Does not count current day, the date returned is the last business day
 * Requires PHP 5.1 (Using ISO-8601 week)
 */

function businessDays($timestamp = false, $bDays = 2) {
    if($timestamp === false) $timestamp = time();
    while ($bDays>0) {
        $timestamp += 86400;
        if (date('N', $timestamp)<6) $bDays--;
    }
    return $timestamp;
}

ตัวแปร 2:

<?php
/*
 * Does not count current day, the date returned is a business day 
 * following the last business day
 * Requires PHP 5.1 (Using ISO-8601 week)
 */

function businessDays($timestamp = false, $bDays = 2) {
    if($timestamp === false) $timestamp = time();
    while ($bDays+1>0) {
        $timestamp += 86400;
        if (date('N', $timestamp)<6) $bDays--;
    }
    return $timestamp;
}

ตัวแปร 3:

<?php
/*
 * Does not count current day, the date returned is 
 * a date following the last business day (can be weekend or not. 
 * See above for alternatives)
 * Requires PHP 5.1 (Using ISO-8601 week)
 */

function businessDays($timestamp = false, $bDays = 2) {
    if($timestamp === false) $timestamp = time();
    while ($bDays>0) {
        $timestamp += 86400;
        if (date('N', $timestamp)<6) $bDays--;
    }
    return $timestamp += 86400;
}

การพิจารณาวันหยุดเพิ่มเติมสามารถทำได้โดยใช้รูปแบบต่างๆข้างต้นโดยทำดังต่อไปนี้ บันทึก! ตรวจสอบให้แน่ใจว่าการประทับเวลาทั้งหมดเป็นเวลาเดียวกันของวัน (เช่นเที่ยงคืน)

สร้างอาร์เรย์ของวันหยุด (เป็น unixtimestamps) เช่น:

$holidays = array_flip(strtotime('2011-01-01'),strtotime('2011-12-25'));

แก้ไขบรรทัด:

if (date('N', $timestamp)<6) $bDays--;

เป็น :

if (date('N', $timestamp)<6 && !isset($holidays[$timestamp])) $bDays--;

เสร็จแล้ว!

<?php
/*
 * Does not count current day, the date returned is the last business day
 * Requires PHP 5.1 (Using ISO-8601 week)
 */

function businessDays($timestamp = false, $bDays = 2) {
    if($timestamp === false) $timestamp = strtotime(date('Y-m-d',time()));
    $holidays = array_flip(strtotime('2011-01-01'),strtotime('2011-12-25'));
    while ($bDays>0) {
        $timestamp += 86400;
        if (date('N', $timestamp)<6 && !isset($holidays[$timestamp])) $bDays--;
    }
    return $timestamp;
}


1

นี่คือโซลูชันแบบวนซ้ำ สามารถแก้ไขได้อย่างง่ายดายเพื่อติดตามและส่งคืนวันที่ล่าสุดเท่านั้น

//  Returns a $numBusDays-sized array of all business dates, 
//  starting from and including $currentDate. 
//  Any date in $holidays will be skipped over.

function getWorkingDays($currentDate, $numBusDays, $holidays = array(), 
  $resultDates = array())
{
  //  exit when we have collected the required number of business days
  if ($numBusDays === 0) {
    return $resultDates;
  }

  //  add current date to return array, if not a weekend or holiday
  $date = date("w", strtotime($currentDate));
  if ( $date != 0  &&  $date != 6  &&  !in_array($currentDate, $holidays) ) {
    $resultDates[] = $currentDate;
    $numBusDays -= 1;
  }

  //  set up the next date to test
  $currentDate = new DateTime("$currentDate + 1 day");
  $currentDate = $currentDate->format('Y-m-d');

  return getWorkingDays($currentDate, $numBusDays, $holidays, $resultDates);
}

//  test
$days = getWorkingDays('2008-12-05', 4);
print_r($days);

1
date_default_timezone_set('America/New_York');


/** Given a number days out, what day is that when counting by 'business' days
  * get the next business day. by default it looks for next business day
  * ie calling  $date = get_next_busines_day(); on monday will return tuesday
  *             $date = get_next_busines_day(2); on monday will return wednesday
  *             $date = get_next_busines_day(2); on friday will return tuesday
  *
  * @param $number_of_business_days (integer)       how many business days out do you want
  * @param $start_date (string)                     strtotime parseable time value
  * @param $ignore_holidays (boolean)               true/false to ignore holidays
  * @param $return_format (string)                  as specified in php.net/date
 */
function get_next_business_day($number_of_business_days=1,$start_date='today',$ignore_holidays=false,$return_format='m/d/y') {

    // get the start date as a string to time
    $result = strtotime($start_date);

    // now keep adding to today's date until number of business days is 0 and we land on a business day
    while ($number_of_business_days > 0) {
        // add one day to the start date
        $result = strtotime(date('Y-m-d',$result) . " + 1 day");

        // this day counts if it's a weekend and not a holiday, or if we choose to ignore holidays
        if (is_weekday(date('Y-m-d',$result)) && (!(is_holiday(date('Y-m-d',$result))) || $ignore_holidays) ) 
            $number_of_business_days--;

    }

    // when my $number of business days is exausted I have my final date

    return(date($return_format,$result));
}

    function is_weekend($date) {
    // return if this is a weekend date or not.
    return (date('N', strtotime($date)) >= 6);
}

function is_weekday($date) {
    // return if this is a weekend date or not.
    return (date('N', strtotime($date)) < 6);
}

function is_holiday($date) {
    // return if this is a holiday or not.

    // what are my holidays for this year
    $holidays = array("New Year's Day 2011" => "12/31/10",
                        "Good Friday" => "04/06/12",
                        "Memorial Day" => "05/28/12",
                        "Independence Day" => "07/04/12",
                        "Floating Holiday" => "12/31/12",
                        "Labor Day" => "09/03/12",
                        "Thanksgiving Day" => "11/22/12",
                        "Day After Thanksgiving Day" => "11/23/12",
                        "Christmas Eve" => "12/24/12",
                        "Christmas Day" => "12/25/12",
                        "New Year's Day 2012" => "01/02/12",
                        "New Year's Day 2013" => "01/01/13"
                        );

    return(in_array(date('m/d/y', strtotime($date)),$holidays));
}


print get_next_business_day(1) . "\n";

1
<?php
// $today is the UNIX timestamp for today's date
$today = time();
echo "<strong>Today is (ORDER DATE): " . '<font color="red">' . date('l, F j, Y', $today) . "</font></strong><br/><br/>";

//The numerical representation for day of week (Ex. 01 for Monday .... 07 for Sunday
$today_numerical = date("N",$today);

//leadtime_days holds the numeric value for the number of business days 
$leadtime_days = $_POST["leadtime"];

//leadtime is the adjusted date for shipdate
$shipdate = time();

while ($leadtime_days > 0) 
{
 if ($today_numerical != 5 && $today_numerical != 6)
 {
  $shipdate = $shipdate + (60*60*24);
  $today_numerical = date("N",$shipdate);
  $leadtime_days --;
 }
 else
  $shipdate = $shipdate + (60*60*24);
  $today_numerical = date("N",$shipdate);
}

echo '<strong>Estimated Ship date: ' . '<font color="green">' . date('l, F j, Y', $shipdate) . "</font></strong>";
?>

1

คำนวณวันทำงานระหว่างวันที่สองวันรวมทั้งวันหยุดและสัปดาห์ทำงานที่กำหนดเอง

คำตอบไม่ใช่เรื่องเล็กน้อย - ดังนั้นคำแนะนำของฉันคือใช้คลาสที่คุณสามารถกำหนดค่าได้มากกว่าการใช้ฟังก์ชันแบบง่าย (หรือสมมติว่ามีสถานที่และวัฒนธรรมที่คงที่) หากต้องการรับวันที่หลังจากวันทำงานจำนวนหนึ่งคุณจะต้อง:

  1. ต้องระบุวันธรรมดาที่คุณจะทำงาน (ค่าเริ่มต้นคือ MON-FRI) - ชั้นเรียนอนุญาตให้คุณเปิดหรือปิดแต่ละวันทำงานทีละวัน
  2. จำเป็นต้องทราบว่าคุณต้องพิจารณาวันหยุดราชการ (ประเทศและรัฐ) ให้ถูกต้อง

แนวทางการทำงาน

/**
 * @param days, int
 * @param $format, string: dateformat (if format defined OTHERWISE int: timestamp) 
 * @param start, int: timestamp (mktime) default: time() //now
 * @param $wk, bit[]: flags for each workday (0=SUN, 6=SAT) 1=workday, 0=day off
 * @param $holiday, string[]: list of dates, YYYY-MM-DD, MM-DD 
 */
function working_days($days, $format='', $start=null, $week=[0,1,1,1,1,1,0], $holiday=[])
{
    if(is_null($start)) $start = time();
    if($days <= 0) return $start;
    if(count($week) != 7) trigger_error('workweek must contain bit-flags for 7 days');
    if(array_sum($week) == 0) trigger_error('workweek must contain at least one workday');
    $wd = date('w', $start);//0=sun, 6=sat
    $time = $start;
    while($days)
    {
        if(
        $week[$wd]
        && !in_array(date('Y-m-d', $time), $holiday)
        && !in_array(date('m-d', $time), $holiday)
        ) --$days; //decrement on workdays
        $wd = date('w', $time += 86400); //add one day in seconds
    }
    $time -= 86400;//include today
    return $format ? date($format, $time): $time;
}

//simple usage
$ten_days = working_days(10, 'D F d Y');
echo '<br>ten workingdays (MON-FRI) disregarding holidays: ',$ten_days;

//work on saturdays and add new years day as holiday
$ten_days = working_days(10, 'D F d Y', null, [0,1,1,1,1,1,1], ['01-01']);
echo '<br>ten workingdays (MON-SAT) disregarding holidays: ',$ten_days;

1

นี่เป็นอีกวิธีหนึ่งซึ่งเร็วกว่าการตรวจสอบวันหยุดด้วย in_array เกือบ 25%:

/**
 * Function to calculate the working days between two days, considering holidays.
 * @param string $startDate -- Start date of the range (included), formatted as Y-m-d.
 * @param string $endDate -- End date of the range (included), formatted as Y-m-d.
 * @param array(string) $holidayDates -- OPTIONAL. Array of holidays dates, formatted as Y-m-d. (e.g. array("2016-08-15", "2016-12-25"))
 * @return int -- Number of working days.
 */
function getWorkingDays($startDate, $endDate, $holidayDates=array()){
    $dateRange = new DatePeriod(new DateTime($startDate), new DateInterval('P1D'), (new DateTime($endDate))->modify("+1day"));
    foreach ($dateRange as $dr) { if($dr->format("N")<6){$workingDays[]=$dr->format("Y-m-d");} }
    return count(array_diff($workingDays, $holidayDates));
}

1

ข้อมูลโค้ดนี้ง่ายมากในการคำนวณวันทำการโดยไม่มีวันสิ้นสุดสัปดาห์และวันหยุด:

function getWorkingDays($startDate,$endDate,$offdays,$holidays){
$endDate = strtotime($endDate);
$startDate = strtotime($startDate);
$days = ($endDate - $startDate) / 86400 + 1;
$counter=0;
for ($i = 1; $i <= $days; $i++) {
    $the_first_day_of_week = date("N", $startDate);
    $startDate+=86400;
if (!in_array($the_first_day_of_week, $offdays) && !in_array(date("Y-m-
d",$startDate), $holidays)) {
$counter++;
}

}   
return $counter;
}
//example to use
$holidays=array("2017-07-03","2017-07-20");
$offdays=array(5,6);//weekend days Monday=1 .... Sunday=7
echo getWorkingDays("2017-01-01","2017-12-31",$offdays,$holidays)

1

ฉันรู้ว่าฉันไปงานปาร์ตี้ช้า แต่ฉันใช้ชุดฟังก์ชันเก่านี้โดย Marcos J. Montes เพื่อหาวันหยุดและวันทำการ เขาใช้เวลาในการเพิ่มอัลกอริทึมจากปีพ. ศ. 2419 สำหรับเทศกาลอีสเตอร์และเพิ่มวันหยุดสำคัญทั้งหมดของสหรัฐฯ สามารถอัปเดตสำหรับประเทศอื่น ๆ ได้อย่างง่ายดาย

//Usage
$days = 30;
$next_working_date = nextWorkingDay($days, $somedate);

//add date function
function DateAdd($interval, $number, $date) {

    $date_time_array = getdate($date);
    //die(print_r($date_time_array));

    $hours = $date_time_array["hours"];
    $minutes = $date_time_array["minutes"];
    $seconds = $date_time_array["seconds"];
    $month = $date_time_array["mon"];
    $day = $date_time_array["mday"];
    $year = $date_time_array["year"];

    switch ($interval) {

        case "yyyy":
            $year+=$number;
            break;
        case "q":
            $year+=($number*3);
            break;
        case "m":
            $month+=$number;
            break;
        case "y":
        case "d":
        case "w":
            $day+=$number;
            break;
        case "ww":
            $day+=($number*7);
            break;
        case "h":
            $hours+=$number;
            break;
        case "n":
            $minutes+=$number;
            break;
        case "s":
            $seconds+=$number; 
            break;            
    }
    //      echo "day:" . $day;
    $timestamp= mktime($hours,$minutes,$seconds,$month,$day,$year);
    return $timestamp;
}

// the following function get_holiday() is based on the work done by
// Marcos J. Montes
function get_holiday($year, $month, $day_of_week, $week="") {
    if ( (($week != "") && (($week > 5) || ($week < 1))) || ($day_of_week > 6) || ($day_of_week < 0) ) {
        // $day_of_week must be between 0 and 6 (Sun=0, ... Sat=6); $week must be between 1 and 5
        return FALSE;
    } else {
        if (!$week || ($week == "")) {
            $lastday = date("t", mktime(0,0,0,$month,1,$year));
            $temp = (date("w",mktime(0,0,0,$month,$lastday,$year)) - $day_of_week) % 7;
        } else {
            $temp = ($day_of_week - date("w",mktime(0,0,0,$month,1,$year))) % 7;
        }

        if ($temp < 0) {
            $temp += 7;
        }

        if (!$week || ($week == "")) {
            $day = $lastday - $temp;
        } else {
            $day = (7 * $week) - 6 + $temp;
        }
        //echo $year.", ".$month.", ".$day . "<br><br>";
        return format_date($year, $month, $day);
    }
}

function observed_day($year, $month, $day) {
    // sat -> fri & sun -> mon, any exceptions?
    //
    // should check $lastday for bumping forward and $firstday for bumping back,
    // although New Year's & Easter look to be the only holidays that potentially
    // move to a different month, and both are accounted for.

    $dow = date("w", mktime(0, 0, 0, $month, $day, $year));

    if ($dow == 0) {
        $dow = $day + 1;
    } elseif ($dow == 6) {
        if (($month == 1) && ($day == 1)) {    // New Year's on a Saturday
            $year--;
            $month = 12;
            $dow = 31;
        } else {
            $dow = $day - 1;
        }
    } else {
        $dow = $day;
    }

    return format_date($year, $month, $dow);
}

function calculate_easter($y) {
    // In the text below, 'intval($var1/$var2)' represents an integer division neglecting
    // the remainder, while % is division keeping only the remainder. So 30/7=4, and 30%7=2
//
    // This algorithm is from Practical Astronomy With Your Calculator, 2nd Edition by Peter
    // Duffett-Smith. It was originally from Butcher's Ecclesiastical Calendar, published in
    // 1876. This algorithm has also been published in the 1922 book General Astronomy by
    // Spencer Jones; in The Journal of the British Astronomical Association (Vol.88, page
    // 91, December 1977); and in Astronomical Algorithms (1991) by Jean Meeus. 

    $a = $y%19;
    $b = intval($y/100);
    $c = $y%100;
    $d = intval($b/4);
    $e = $b%4;
    $f = intval(($b+8)/25);
    $g = intval(($b-$f+1)/3);
    $h = (19*$a+$b-$d-$g+15)%30;
    $i = intval($c/4);
    $k = $c%4;
    $l = (32+2*$e+2*$i-$h-$k)%7;
    $m = intval(($a+11*$h+22*$l)/451);
    $p = ($h+$l-7*$m+114)%31;
    $EasterMonth = intval(($h+$l-7*$m+114)/31);    // [3 = March, 4 = April]
    $EasterDay = $p+1;    // (day in Easter Month)

    return format_date($y, $EasterMonth, $EasterDay);
}


function nextWorkingDay($number_days, $start_date = "") {
    $day_counter = 0;
    $intCounter = 0;    

    if ($start_date=="") {
        $today  = mktime(0, 0, 0, date("m")  , date("d"), date("Y"));
    } else {
        $start_time = strtotime($start_date);
        $today  = mktime(0, 0, 0, date("m", $start_time)  , date("d", $start_time), date("Y", $start_time));
    }

    while($day_counter < $number_days) {
        $working_time = DateAdd("d", 1, $today);
        $working_date = date("Y-m-d", $working_date);
        if (!isWeekend($working_date) && !confirm_holiday(date("Y-m-d", strtotime($working_date))) ) {
            $day_counter++;
        }
        $intCounter++;
        $today  = $working_time;
        if ($intCounter > 1000) {
            //just in case out of control?
            break;
        }
    }

    return $working_date;
}
function isWeekend($check_date) {
    return (date("N",  strtotime($check_date)) > 5);
}
function confirm_holiday($somedate="") {
    if ($somedate=="") {
        $somedate = date("Y-m-d");
    }
    $year = date("Y", strtotime($somedate));
    $blnHoliday = false;
    //newyears
    if ($somedate == observed_day($year, 1, 1)) {
        $blnHoliday = true;
    }
    if ($somedate == format_date($year, 1, 1)) {
        $blnHoliday = true;
    }
    if ($somedate == format_date($year, 12, 31)) {
        $blnHoliday = true;
    }
    //Martin Luther King
    if ($somedate == get_holiday($year, 1, 1, 3)) {
        $blnHoliday = true;
    }
    //President's
    if ($somedate == get_holiday($year, 2, 1, 3)) {
        $blnHoliday = true;
    }
    //easter
    if ($somedate == calculate_easter($year)) {
        $blnHoliday = true;
    }
    //Memorial
    if ($somedate == get_holiday($year, 5, 1)) {
        $blnHoliday = true;
    }
    //july4
    if ($somedate == observed_day($year, 7, 4)) {
        $blnHoliday = true;
    }
    //labor
    if ($somedate == get_holiday($year, 9, 1, 1)) {
        $blnHoliday = true;
    }
    //columbus
    if ($somedate == get_holiday($year, 10, 1, 2)) {
        $blnHoliday = true;
    }
    //thanks
    if ($somedate == get_holiday($year, 11, 4, 4)) {
        $blnHoliday = true;
    }
    //xmas
    if ($somedate == format_date($year, 12, 24)) {
        $blnHoliday = true;
    }
    if ($somedate == format_date($year, 12, 25)) {
        $blnHoliday = true;
    }
    return $blnHoliday;
}

0

ฟังก์ชัน get_business_days_forward_from_date ($ num_days, $ start_date = '', $ rtn_fmt = 'Ym-d') {

// $start_date will default to today    

if ($start_date=='') { $start_date = date("Y-m-d"); }

$business_day_ct = 0;

$max_days = 10000 + $num_days;  // to avoid any possibility of an infinite loop


// define holidays, this currently only goes to 2012 because, well, you know... ;-)
// if the world is still here after that, you can find more at
// http://www.opm.gov/Operating_Status_Schedules/fedhol/2013.asp
// always add holidays in order, because the iteration will stop when the holiday is > date being tested

$fed_holidays=array(
    "2010-01-01",
    "2010-01-18",
    "2010-02-15",
    "2010-05-31",
    "2010-07-05",
    "2010-09-06",
    "2010-10-11",
    "2010-11-11",
    "2010-11-25",
    "2010-12-24",

    "2010-12-31",
    "2011-01-17",
    "2011-02-21",
    "2011-05-30",
    "2011-07-04",
    "2011-09-05",
    "2011-10-10",
    "2011-11-11",
    "2011-11-24",
    "2011-12-26",

    "2012-01-02",
    "2012-01-16",
    "2012-02-20",
    "2012-05-28",
    "2012-07-04",
    "2012-09-03",
    "2012-10-08",
    "2012-11-12",
    "2012-11-22",
    "2012-12-25",
    );

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

for ($x=1;$x<$max_days;$x++)
{
    if (intval($num_days)==intval($business_day_ct)) { return(date($rtn_fmt, strtotime($curr_date_ymd))); }  // date found - return

    // get next day to check

    $curr_date_ymd = date('Y-m-d', (strtotime($start_date)+($x * 86400)));   // add 1 day to the current date

    $is_business_day = 1;

    // check if this is a weekend   1 (for Monday) through 7 (for Sunday)

    if ( intval(date("N",strtotime($curr_date_ymd))) > 5) { $is_business_day = 0; }

    //check for holiday
    foreach($fed_holidays as $holiday)
    {
        if (strtotime($holiday)==strtotime($curr_date_ymd))  // holiday found
        {
            $is_business_day = 0;
            break 1;
        }

        if (strtotime($holiday)>strtotime($curr_date_ymd)) { break 1; }  // past date, stop searching (always add holidays in order)


    }

    $business_day_ct = $business_day_ct + $is_business_day;  // increment if this is a business day

} 

// if we get here, you are hosed
return ("ERROR");

}


0

add_business_days มีข้อบกพร่องเล็กน้อย ลองทำสิ่งต่อไปนี้ด้วยฟังก์ชันที่มีอยู่และผลลัพธ์จะเป็นวันเสาร์

วันที่เริ่มต้น = วันทำการวันศุกร์ที่จะเพิ่ม = 1 อาร์เรย์วันหยุด = เพิ่มวันที่สำหรับวันจันทร์ถัดไป

ฉันได้แก้ไขในฟังก์ชันด้านล่างแล้ว

function add_business_days($startdate, $buisnessdays, $holidays = array(), $dateformat = 'Y-m-d'){
$i= 1;
$dayx= strtotime($startdate);
$buisnessdays= ceil($buisnessdays);

while($i < $buisnessdays)
{
    $day= date('N',$dayx);

    $date= date('Y-m-d',$dayx);
    if($day < 6 && !in_array($date,$holidays))
        $i++;

    $dayx= strtotime($date.' +1 day');
}

## If the calculated day falls on a weekend or is a holiday, then add days to the next business day
$day= date('N',$dayx);
$date= date('Y-m-d',$dayx);

while($day >= 6 || in_array($date,$holidays))
{
    $dayx= strtotime($date.' +1 day');
    $day= date('N',$dayx);
    $date= date('Y-m-d',$dayx);
}

return date($dateformat, $dayx);}

ฉันคิดว่านี่เป็นไปตามรหัสของ Bobbin ฉันเชื่อว่าฉันได้แก้ไขปัญหานี้เช่นกัน
mcgrailm

0

ฉันเพิ่งให้ฟังก์ชันของฉันทำงานตามรหัส Bobbin และ mcgrailm เพิ่มบางสิ่งที่ทำงานได้อย่างสมบูรณ์แบบสำหรับฉัน

function add_business_days($startdate,$buisnessdays,$holidays,$dateformat){
    $enddate = strtotime($startdate);
    $day = date('N',$enddate);
    while($buisnessdays > 0){ // compatible with 1 businessday if I'll need it
        $enddate = strtotime(date('Y-m-d',$enddate).' +1 day');
        $day = date('N',$enddate);
        if($day < 6 && !in_array(date('Y-m-d',$enddate),$holidays))$buisnessdays--;
    }
    return date($dateformat,$enddate);
}

// as a parameter in in_array function we should use endate formated to 
// compare correctly with the holidays array.

1
ความแตกต่างเพียงอย่างเดียวระหว่างของฉันและของคุณคือของฉันเป็นหนึ่งเดียวโดยอิงจากคุณเป็นศูนย์ คุณไม่ได้ทำอะไรที่นี่จริงๆ ฉันยินดีที่รหัสนี้ช่วยคุณได้ อย่างไรก็ตามฉันไม่ถือว่าเป็นรหัสที่ "อิงตาม" มันเหมือนกับการที่คุณพยายามอ้างรหัสของฉันเป็นของคุณเอง
mcgrailm

0

การปรับปรุงฟังก์ชันที่นำเสนอโดย James Pasta ด้านบนเพื่อรวมวันหยุดของรัฐบาลกลางทั้งหมดและเพื่อแก้ไขวันที่ 4 กรกฎาคม (คำนวณเป็นวันที่ 4 มิถุนายนข้างต้น!) และรวมชื่อวันหยุดเป็นคีย์อาร์เรย์ ...

/ **
* วันหยุดประจำชาติของอเมริกา
* @param string $ year
* @return array
* /
public static function getNationalAmericanHolidays ($ year) {

//  January 1 - New Year's Day (Observed)
//  Third Monday in January - Birthday of Martin Luther King, Jr.
//  Third Monday in February - Washington’s Birthday / President's Day
//  Last Monday in May - Memorial Day
//  July 4 - Independence Day
//  First Monday in September - Labor Day
//  Second Monday in October - Columbus Day
//  November 11 - Veterans’ Day (Observed)
//  Fourth Thursday in November Thanksgiving Day
//  December 25 - Christmas Day
$bankHolidays = array(
    ['New Years Day'] => $year . "-01-01",
    ['Martin Luther King Jr Birthday'] => "". date("Y-m-d",strtotime("third Monday of January " . $year) ),
    ['Washingtons Birthday'] => "". date("Y-m-d",strtotime("third Monday of February " . $year) ),
    ['Memorial Day'] => "". date("Y-m-d",strtotime("last Monday of May " . $year) ),
    ['Independance Day'] => $year . "-07-04",
    ['Labor Day'] => "". date("Y-m-d",strtotime("first Monday of September " . $year) ),
    ['Columbus Day'] => "". date("Y-m-d",strtotime("second Monday of October " . $year) ),
    ['Veterans Day'] => $year . "-11-11",
    ['Thanksgiving Day'] => "". date("Y-m-d",strtotime("fourth Thursday of November " . $year) ),
    ['Christmas Day'] => $year . "-12-25"
);

return $bankHolidays;

}


0

เพิ่งเสร็จสิ้นการเขียน API ที่สามารถใช้เพื่อจัดการกับวันทำการ (ไม่มีวิธีใดที่ใช้ได้ผลกับสถานการณ์ของฉัน :-); ลิงค์ไปที่นี่เผื่อว่าใครเห็นว่ามีประโยชน์

~ เนท

PHP Class เพื่อคำนวณวันทำการ


0

ขอบคุณ Bobbin, mcgrailm, Tony, James Pasta และอีกสองสามคนที่โพสต์ที่นี่ ฉันเขียนฟังก์ชันของตัวเองเพื่อเพิ่มวันทำการเป็นวันที่ แต่แก้ไขด้วยรหัสบางส่วนที่ฉันพบที่นี่ สิ่งนี้จะจัดการกับวันที่เริ่มต้นซึ่งเป็นวันหยุดสุดสัปดาห์ / วันหยุด นอกจากนี้ยังรองรับเวลาทำการ ฉันเพิ่มความคิดเห็นและแยกโค้ดออกเพื่อให้อ่านง่ายขึ้น

<?php
function count_business_days($date, $days, $holidays) {
    $date = strtotime($date);

    for ($i = 1; $i <= intval($days); $i++) { //Loops each day count

        //First, find the next available weekday because this might be a weekend/holiday
        while (date('N', $date) >= 6 || in_array(date('Y-m-d', $date), $holidays)){
            $date = strtotime(date('Y-m-d',$date).' +1 day');
        }

        //Now that we know we have a business day, add 1 day to it
        $date = strtotime(date('Y-m-d',$date).' +1 day');

        //If this day that was previously added falls on a weekend/holiday, then find the next business day
        while (date('N', $date) >= 6 || in_array(date('Y-m-d', $date), $holidays)){
            $date = strtotime(date('Y-m-d',$date).' +1 day');
        }
    }
    return date('Y-m-d', $date);
}

//Also add in the code from Tony and James Pasta to handle holidays...

function getNationalAmericanHolidays($year) {
$bankHolidays = array(
    'New Years Day' => $year . "-01-01",
    'Martin Luther King Jr Birthday' => "". date("Y-m-d",strtotime("third Monday of January " . $year) ),
    'Washingtons Birthday' => "". date("Y-m-d",strtotime("third Monday of February " . $year) ),
    'Memorial Day' => "". date("Y-m-d",strtotime("last Monday of May " . $year) ),
    'Independance Day' => $year . "-07-04",
    'Labor Day' => "". date("Y-m-d",strtotime("first Monday of September " . $year) ),
    'Columbus Day' => "". date("Y-m-d",strtotime("second Monday of October " . $year) ),
    'Veterans Day' => $year . "-11-11",
    'Thanksgiving Day' => "". date("Y-m-d",strtotime("fourth Thursday of November " . $year) ),
    'Christmas Day' => $year . "-12-25"
);
return $bankHolidays;

}

//Now to call it... since we're working with business days, we should
//also be working with business hours so check if it's after 5 PM
//and go to the next day if necessary.

//Go to next day if after 5 pm (5 pm = 17)
if (date(G) >= 17) {
    $start_date = date("Y-m-d", strtotime("+ 1 day")); //Tomorrow
} else {
    $start_date = date("Y-m-d"); //Today
}

//Get the holidays for the current year and also for the next year
$this_year = getNationalAmericanHolidays(date('Y'));
$next_year = getNationalAmericanHolidays(date('Y', strtotime("+12 months")));
$holidays = array_merge($this_year, $next_year);

//The number of days to count
$days_count = 10;

echo count_business_days($start_date, $days_count, $holidays);

?>

0

โดยส่วนตัวแล้วฉันคิดว่านี่เป็นวิธีแก้ปัญหาที่สะอาดและรัดกุมมากขึ้น:

function onlyWorkDays( $d ) {
    $holidays = array('2013-12-25','2013-12-31','2014-01-01','2014-01-20','2014-02-17','2014-05-26','2014-07-04','2014-09-01','2014-10-13','2014-11-11','2014-11-27','2014-12-25','2014-12-31');
    while (in_array($d->format("Y-m-d"), $holidays)) { // HOLIDAYS
        $d->sub(new DateInterval("P1D"));
    }
    if ($d->format("w") == 6) { // SATURDAY
        $d->sub(new DateInterval("P1D"));
    }
    if ($d->format("w") == 0) { // SUNDAY
        $d->sub(new DateInterval("P2D"));
    }
    return $d;
}

เพียงส่งnewวันที่ที่เสนอมาที่ฟังก์ชันนี้

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.