Error calculating the difference of PHP days

I have PHP code to calculate the number of days between two specific dates. The difference should not be taken into account on Sundays and Saturdays. In addition, I have an array of dates that includes holidays that you must also skip.

I gave the start date as 01-05-2015 and the end date as 01-06-2015 . I gave whole days in the month of May, like an array. Therefore, the difference should be 1 day. But I get the output as 7. What is the problem? Here is the code.

 function dateRange($first, $last) { $dates = array(); $current = strtotime($first); $now = $current; $last = strtotime($last); while( $current <= $last ) { if (date('w', $current) != 0){ $dates[] = date('dm-Y', $current); } $current = strtotime('+1 day', $current); } unset($dates[0]); return $dates; } $datea = "01-05-2015"; $date = "01-06-2015"; $hdsarray = array("1-05-2015","2-05-2015","4-05-2015","5-05-2015","7-05-2015","8-05-2015","9-05-2015","11-05-2015","12-05-2015","14-05-2015","15-05-2015","16-05-2015","18-05-2015","19-05-2015","21-05-2015","22-05-2015","23-05-2015","25-05-2015","26-05-2015","28-05-2015","29-05-2015","30-05-2015"); $datesarray = dateRange($datea, $date); $result = array_diff($hdsarray,$datesarray); $date_diff = sizeof($result); echo $date_diff; 
+6
source share
3 answers

The problem that I see only in using array_diff actually includes sat and sun, which are excluded by the dateRange function if they are not found in the holidays list.

Instead, you can pass the vacation dates in the dateRange function and filter there.

 function dateRange($first, $last, $excludeDates) { $dates = array(); $current = strtotime($first); $now = $current; $last = strtotime($last); while( $current <= $last ) { if (date('w', $current) != 0 && date('w', $current) != 6 && !in_array(date('jm-Y', $current), $excludeDates)){ $dates[] = date('dm-Y', $current); } $current = strtotime('+1 day', $current); } // unset($dates[0]); return $dates; } $datea = "01-05-2015"; $date = "01-06-2015"; $hdsarray = array("1-05-2015","2-05-2015","4-05-2015","5-05-2015","7-05-2015","8-05-2015","9-05-2015","11-05-2015","12-05-2015","14-05-2015","15-05-2015","16-05-2015","18-05-2015","19-05-2015","21-05-2015","22-05-2015","23-05-2015","25-05-2015","26-05-2015","28-05-2015","29-05-2015","30-05-2015"); $datesarray = dateRange($datea, $date, $hdsarray);print_r($datesarray); 

Result:

 Array ( [0] => 06-05-2015 [1] => 13-05-2015 [2] => 20-05-2015 [3] => 27-05-2015 [4] => 01-06-2015 ) 

All 5 dates come as a result, do not sit, do not have the sun, and also are not present in the list of holidays.

+3
source

There seems to be a few issues here. First, as others noted, the condition:

 if (date('w', $current) != 0){ 

Sunday only, if it should also include Saturday, it should be:

 if (date('w', $current) != 0 && date('w', $current) != 6){ 

Secondly, it seems that the $hdsarray array $hdsarray not contain all the days in May. It seems that all environments are missing.

The third problem is that you are using array_diff on two arrays, one of which contains Dates, and the other - Strings. From the documentation:

Two elements are considered equal if and only if (string) $ elem1 === (string) $ elem2. In words: when the string representation is the same.

In your $hdsarray you use "1-05-2015" to indicate the first day of the month, and:

  echo date('dm-Y', strtotime("1-05-2015")); 

leads to "01-05-2015" . You will need to add an extra 0 to $hdsarray for these dates or work with dates.

Last but not least, the current algorithm does not work correctly if $hdsarray contains dates for Saturday or Sunday, the result of array_diff will contain these dates. Since you want to filter the result of a daterange , the array_filter function might be more appropriate.

0
source

Although the answer has already been provided, here is a small snippet with a class that handles everything for you:

 <?php class dateRange { protected $start, $end, $daysToExclude, $datesToExclude; function __construct($dateStart, $dateEnd, $daysToExclude, $datesToExclude) { $this->start = $dateStart; $this->end = $dateEnd; $this->daysToExclude = $daysToExclude; $this->datesToExclude = $this->fixFormat($datesToExclude); } public function getRangeLength ($callback = null) { $tmp = array(); $now = strtotime($this->start); $to = strtotime($this->end); while ( $now <= $to ) { if (!in_array(date("w", $now), $this->daysToExclude)) { $tmp[] = date('dm-Y', $now); } $now = strtotime('+1 day', $now); } is_callable($callback) && call_user_func($callback, array_diff($tmp,$this->datesToExclude)); return count(array_diff($tmp,$this->datesToExclude)); } private function fixFormat($el) { if (!is_array($el)) { return false; } else { foreach ($el as &$value) { $value = date("dmY",strtotime($value)); } return $el; } } } ?> 

I decided to keep your current logic (using date_diff), but I thought that in the future you might have your boss telling you: “You know what? I don’t want to have Mondays there”, so with the current system you will have to manually edit your function and you may no longer remember what you did.

The class above expects four parameters:

  • dateStart (dmY format)
  • dateEnd (dmY format)
  • daysToExclude (array with day identifiers to exclude -> array example (0.6) to exclude Saturday and Sunday).
  • dateToExclude (an array with dates for exceptions, each supported format).

The class will automatically correct the format of the dateToExclude array so that you can use date_diff.

Here is a usage example, following your case:

 <?php $dateStart = "01-05-2015"; $dateEnd = "01-06-2015"; $daysToExclude = array(0,6); $exclusions = array( "1-05-2015", "2-05-2015", "4-05-2015", "5-05-2015", "7-05-2015", "8-05-2015", "9-05-2015", "11-05-2015", "12-05-2015", "14-05-2015", "15-05-2015", "16-05-2015", "18-05-2015", "19-05-2015", "21-05-2015", "22-05-2015", "23-05-2015", "25-05-2015", "26-05-2015", "28-05-2015", "29-05-2015", "30-05-2015" ); $dateRange = new dateRange($dateStart, $dateEnd, $daysToExclude, $exclusions); echo $dateRange->getRangeLength(); ?> 

The code above produces 5.

The getRangeLength function also takes a callback and returns an array result of the date_diff operation, so you can also:

 $dateRange->getRangeLength(function($res) { echo "Literal output: <br />"; print_r($res); echo "<br />count is: " . count($res); }); 

The above outputs:

 Literal output: Array ( [3] => 06-05-2015 [8] => 13-05-2015 [13] => 20-05-2015 [18] => 27-05-2015 [21] => 01-06-2015 ) count is: 5 

So, if you later also need to remove Mondays, you can easily do this by changing daysToExclude to array(0,1,6);

I hope this will be useful for everyone who needs it, despite the fact that a valid answer has already been posted.

In any case, your original problem was largely related to the array_diff function, which did NOT do its job because the date strings were incompatible, because "01-01-2015" differs from "01-01-2015" if you do not first convert them to time, and then back to dates.

0
source

Source: https://habr.com/ru/post/988771/


All Articles