webentwicklung-frage-antwort-db.com.de

Arbeitstage berechnen

Ich brauche eine Methode zum Hinzufügen von "Werktagen" in PHP. Zum Beispiel Freitag 12/5 + 3 Werktage = Mittwoch 12/10.

Zumindest brauche ich den Code, um die Wochenenden zu verstehen, aber im Idealfall sollte er auch die Bundesferien der USA berücksichtigen. Ich bin mir sicher, dass ich bei Bedarf eine Lösung mit brutaler Gewalt finden könnte, aber ich hoffe, dass es da draußen einen eleganteren Ansatz gibt. Jemand?

Vielen Dank.

95
AdamTheHutt

Hier ist eine Funktion aus der Benutzerkommentare auf der Funktionsseite date () im Handbuch PHP. Es ist eine Verbesserung einer früheren Funktion in den Kommentaren, die Unterstützung für Schaltjahre hinzufügt.

Geben Sie das Start- und Enddatum zusammen mit einem Array möglicher dazwischen liegender Feiertage ein. Die Arbeitstage werden als Ganzzahl zurückgegeben:

<?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
?>
96
flamingLogos

Holen Sie sich die Anzahl der Arbeitstage ohne Feiertage zwischen zwei Terminen:

Beispiel verwenden:

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

Ausgabe:

3

Funktion:

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;
}
81
Glavić

Es gibt einige Argumente für die Funktion date () , die helfen sollten. Wenn Sie das Datum ("w") überprüfen, erhalten Sie eine Nummer für den Wochentag, von 0 für Sonntag bis 6 für Samstag. Also .. vielleicht etwas wie ..

$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;

Dies ist nur ein grobes Beispiel für eine Möglichkeit.

12
Tim

Die Feiertagsberechnung ist in jedem Bundesstaat nicht Standard. Ich schreibe eine Bankanwendung, für die ich einige Geschäftsregeln brauche, aber immer noch nur einen ungefähren Standard erhalten kann.

/**
 * 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;
}
11
James Pasta
$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
Suresh Kamrushi

Hier ist eine Funktion zum Hinzufügen von Geschäftstagen zu einem Datum

 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');

Ein anderer Beitrag erwähnt getWorkingDays (aus php.net-Kommentaren und hier enthalten), aber ich denke, es bricht, wenn Sie an einem Sonntag beginnen und an einem Arbeitstag enden.

Verwenden Sie Folgendes (Sie müssen die getWorkingDays-Funktion aus dem vorherigen Beitrag einschließen.)

 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);

Ergibt das Ergebnis als 5 und nicht 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 

Die folgende Funktion wurde verwendet, um das Obige zu generieren.

     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);

Bring an den Feiertagen ...

6
Bobbin

Brute-Versuch, die Arbeitszeit zu ermitteln - Montag bis Freitag 8-16 Uhr

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

Meine Version basiert auf der Arbeit von @mcgrailm ... wurde angepasst, da der Bericht innerhalb von 3 Werktagen überprüft werden musste. Wenn er an einem Wochenende eingereicht wird, beginnt die Zählung am folgenden Montag:

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;
}

Und die Differenz zwischen zwei Terminen in Bezug auf Werktage berechnen:

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;
}

Als Hinweis, jeder, der 86400 oder 24 * 60 * 60 verwendet, tut bitte nicht ... Ihre vergessene Zeit ändert sich von der Winter-/Sommerzeit, wo es an einem Tag nicht genau 24 Stunden ist. Während die Strtotime etwas langsamer ist ('+ 1 Tag', $ timestamp), ist sie viel zuverlässiger.

2
Craig Francis

Sie können diese einfachere Funktion ausprobieren.

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
George John

Eine Funktion zum Hinzufügen oder Abziehen von Geschäftstagen von einem bestimmten Datum. Dies gilt nicht für Feiertage.

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;
}

verwenden Sie wie so ...

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

Hier ist eine weitere Lösung ohne for-Schleife für jeden Tag.

$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
Laird

Erstellen Sie für Feiertage eine Reihe von Tagen in einem Format, das date () erzeugen kann. Beispiel:

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

Verwenden Sie dann die Funktionen in_array () und date () , um zu prüfen, ob der Zeitstempel einen Feiertag darstellt:

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

Nachfolgend finden Sie den Arbeitscode zur Berechnung der Arbeitswerktage ab einem bestimmten Datum.

<?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"
1
easycodingclub

Variante 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;
}

Variante 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;
}

Variante 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;
}

Die zusätzlichen Feiertagsüberlegungen können unter Verwendung von Variationen des Vorstehenden gemacht werden, indem Sie Folgendes tun. Hinweis! Stellen Sie sicher, dass alle Zeitstempel dieselbe Tageszeit (d. h. Mitternacht) sind. 

Machen Sie eine Reihe von Feiertagsdaten (als Unix-Zeitmarken), d. H .:

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

Zeile ändern: 

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

sein :

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

Erledigt!

<?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
pawpro

Ich hatte das gleiche Bedürfnis, ich begann mit Bobbins erstem Beispiel und endete damit

  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);
  }

jemand

1
mcgrailm
<?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
Vijay

Hier ist eine rekursive Lösung. Es kann leicht geändert werden, um nur das letzte Datum zu verfolgen und zurückzugeben.

//  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
shepardtone
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
James
<?php 
function AddWorkDays(){
$i = 0;
$d = 5; // Number of days to add

    while($i <= $d) {
    $i++;
        if(date('N', mktime(0, 0, 0, date(m), date(d)+$i, date(Y))) < 5) {
            $d++;
        }
    }
    return date(Y).','.date(m).','.(date(d)+$d);
}
?>
1
marve

Dies ist eine weitere Lösung, sie ist fast 25% schneller als die Überprüfung von Feiertagen mit in_array:

/**
 * 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));
}
0
Enrico

Danke an Bobbin, Mcgrailm, Tony, James Pasta und ein paar andere, die hier gepostet haben. Ich hatte meine eigene Funktion geschrieben, um Werktage zu einem Datum hinzuzufügen, habe sie jedoch mit Code geändert, den ich hier gefunden habe. Damit wird das Startdatum an einem Wochenende/Feiertag behandelt. Damit werden auch Geschäftszeiten erledigt. Ich habe einige Kommentare hinzugefügt und den Code aufgeschlüsselt, um das Lesen zu erleichtern.

<?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
Dustin W

Dieses Code-Snippet ist sehr einfach, um den Arbeitstag ohne Wochenende und Feiertage zu berechnen:

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)
0
Mahmoud Obaid

funktion get_business_days_forward_from_date ($ num_days, $ start_date = '', $ rtn_fmt = 'Y-m-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
Richard Varno

Ich persönlich denke, dass dies eine sauberere und prägnantere Lösung ist:

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;
}

Senden Sie einfach das vorgeschlagene new-Datum an diese Funktion.

0
DevlshOne

Arbeitstage zwischen zwei Terminen berechnen, einschließlich Feiertage und benutzerdefinierte Arbeitswochen

Die Antwort ist nicht so trivial - daher würde ich vorschlagen, eine Klasse zu verwenden, in der Sie mehr konfigurieren können, als sich auf eine vereinfachte Funktion zu verlassen (oder eine feste Sprache und Kultur anzunehmen). Um das Datum nach einer bestimmten Anzahl von Arbeitstagen abzurufen, führen Sie folgende Schritte aus:

  1. sie müssen angeben, an welchen Wochentagen Sie arbeiten (standardmäßig MON-FRI). In dieser Klasse können Sie jeden Wochentag einzeln aktivieren oder deaktivieren.
  2. sie müssen wissen, dass Sie gesetzliche Feiertage (Land und Staat) berücksichtigen müssen, um genau zu sein

Funktionsansatz

/**
 * @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;
0
Ian Carter

PHPClasses haben eine Nice-Klasse mit dem Namen PHP Arbeitstage . Sie können diese Klasse überprüfen.

0
Tareq

Ich habe gerade diese Funktion erstellt, die sehr gut funktioniert:

function getBusinessDays($date1, $date2){

    if(!is_numeric($date1)){
        $date1 = strtotime($date1);
    }

    if(!is_numeric($date2)){
        $date2 = strtotime($date2);
    }

    if($date2 < $date1){
        $temp_date = $date1;
        $date1 = $date2;
        $date2 = $temp_date;
        unset($temp_date);
    }

    $diff = $date2 - $date1;

    $days_diff = intval($diff / (3600 * 24));
    $current_day_of_week = intval(date("N", $date1));
    $business_days = 0;

    for($i = 1; $i <= $days_diff; $i++){
        if(!in_array($current_day_of_week, array("Sunday" => 1, "Saturday" => 7))){
            $business_days++;
        }

        $current_day_of_week++;
        if($current_day_of_week > 7){
            $current_day_of_week = 1;
        }
    }

    return $business_days;
}

echo "Business days: " . getBusinessDays("8/15/2014", "8/8/2014");
0
Big Joe

Der add_business_days hat einen kleinen Fehler. Versuchen Sie Folgendes mit der vorhandenen Funktion und die Ausgabe wird ein Samstag sein.

Startdatum = FreitagBusiness Tage zum Hinzufügen = 1 Feiertags-Array = Datum für den folgenden Montag hinzufügen.

Ich habe das in meiner Funktion unten behoben.

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);}
0
Pratik Thakkar

Wenn Sie wissen möchten, wie viel Zeit zwischen zwei Daten liegt, können Sie https://github.com/maximnara/business-days-counter verwenden. Es funktioniert einfach, aber nur mit laravel now $diffInSeconds = $this->datesCounter->getDifferenceInSeconds(Carbon::create(2019, 1, 1), Carbon::now(), DateCounter::COUNTRY_FR);

Es werden keine Feiertage und Wochenenden gezählt und Sie können ein Arbeitsintervall einstellen, z. B. von 9 bis 18 mit Startstunde oder Nein.

Oder wenn Sie nur Wochenenden brauchen und Carbon verwenden, können Sie die eingebaute Funktion verwenden:

$date1 = Carbon::create(2019, 1, 1)->endOfDay();
$date2 = $dt->copy()->startOfDay();
$diff = $date1->diffFiltered(CarbonInterval::minute(), function(Carbon $date) {
   return !$date->isWeekend();
}, $date2, true);

Aber es wird jede Minute im Intervall gesucht, für Bit-Intervalle kann es eine Weile dauern.

0
Max Luzhkov

Ich bekomme nur meine Funktion, die auf Bobbin- und Mcgrailm-Code basiert, und fügt einige Dinge hinzu, die für mich perfekt funktionierten.

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.
0
FAOM

Eine Verbesserung der oben von James Pasta angebotenen Funktion, um alle Bundesfeiertage einzubeziehen und den 4. Juli zu korrigieren (wurde als 4. Juni berechnet!) Sowie den Feiertagsnamen als Array-Schlüssel aufzunehmen ...

/ **
* Nationale amerikanische Feiertage
* @param String $ year
* @return array
* /
öffentliche statische Funktion 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
Tony

Ich weiß, dass ich zu spät zur Party komme, aber ich benutze diese alten Funktionen von Marcos J. Montes, um Feiertage und Arbeitstage zu ermitteln. Er nahm sich die Zeit, um einen Algorithmus von 1876 zu Ostern hinzuzufügen, und er fügte alle wichtigen US-amerikanischen Feiertage hinzu. Dies kann leicht für andere Länder aktualisiert werden.

//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

Ich habe gerade ein API geschrieben, mit dem man Arbeitstage manipulieren kann (keine dieser Lösungen funktionierte für meine Situation :-); Verlinkung hier, falls es für andere nützlich ist.

~ Nate

PHP Klasse zur Berechnung von Geschäftstagen

0