0

I have code that counts working days of absence in current month.
It works well if in month i need to count absence only has one period for person.
Dates from and till are saved on database.
Example 2016-08-09 - 2016-08-13 (lets say user was sick) it counts 4 working days

But if user have:

2016-07-27 - 2016-08-02 (lets say user was sick)
2016-08-08 - 2016-08-10 (lets say user was on vocation) and
2016-08-24 - 2016-09-02 (lets say again user was sick)
how to count all days in absence periods for this month 2016 August? In this case should be 12 days

Getting from database:

 $getaways =  mysqli_query($conn, "SELECT * FROM employeesAbsence WHERE workerID='".$row['worker']."' AND fromDate LIKE  '%2016-08%' AND toDate LIKE  '%2016-08%'); 
 $aways_row = mysqli_fetch_array($getaways);

        $fDate = $aways_row['fromDate'];
        $tDate = $aways_row['toDate'];

Counting code:

$startDate = $fDate;
$endDate =  $tDate; 
$weekdays = array('1','2','3','4','5'); //monday-friday

$begin = new DateTime($startDate);
$end = new DateTime($endDate);

$end = $end->modify( '+1 day' ); //add one day so as to include the end date of our range

$interval = new DateInterval('P1D'); // 1 Day
$dateRange = new DatePeriod($begin, $interval, $end);

$total_days = 0;
//this will calculate total days from monday to friday in above date range
foreach ($dateRange as $dates) {

 if (in_array($dates->format("N"),$weekdays)) {
        $total_days++; 
  }
}
echo $total_days;
Ingus
  • 1,026
  • 12
  • 34
  • 2016-09-27 - 2016-08-02 user is sick almost the full month, plus almost all of september – Andreas Nov 23 '16 at 08:15
  • yes but i need count days in August only – Ingus Nov 23 '16 at 08:18
  • I don't think you understand my point. According to your example, the user is sick the whole time, but you still want to count him as on vaccation during the same timeperiod, and sick again (doublesick)? – Andreas Nov 23 '16 at 08:23
  • Off topic: it is bad juju to use a `%` at the start of any SQL like clause. This will prevent the DB from using any index (possibly) causing the DB to scan through the whole table to determine the result set. Just use `fromDate BETWEEN '2016-08-01' AND '2016-08-31'` MySQL will make sense of the date format. – irundaia Nov 23 '16 at 08:24
  • @Andreas edited it needed to be 2016-07 not 2016-09 – Ingus Nov 23 '16 at 08:25
  • @irundaia how will i skip non working days? – Ingus Nov 23 '16 at 08:40

2 Answers2

1

You could likely do this entirely in the sql query - not tested but I think it should be ok.

For example:

select sum( datediff(`toDate`,`fromDate`) ) as 'sickdays' 
   from `employeesabsence`
   where `workerID`=$row['worker']

You could add additional conditions to the where clause to restrict to specific date range - like this perhaps:

select sum( datediff(`todate`,`fromdate`) ) as 'sickdays' 
    from `employeesabsence` 
    where `workerid`=$row['worker'] and month( `fromdate` ) between 1 and 6;

The solution, in sql, to find working days is a little trickier and the following was adapted from another post found on stack - it involves a peculiar looking string of integers.

For example

select 
sum( 5 * ( datediff( `todate`, `fromdate` ) div 7 ) + mid( '0123455401234434012332340122123401101234000123450', 7 * weekday(`fromdate`) + weekday(`todate`) + 1, 1) ) as 'sickdays'
from `employeesabsence` where month(`fromdate`) between 6 and 7

The post from which this was adapted can be found here

Community
  • 1
  • 1
Professor Abronsius
  • 33,063
  • 5
  • 32
  • 46
  • I never think about this! OMW to try this out! – Ingus Nov 23 '16 at 08:27
  • The bad thing is that it count in non working days to (i mean Saturday and Sunday) – Ingus Nov 23 '16 at 08:52
  • I m using first query with last query SUM and it seems it takes 1 extra day off.Could it be first or last day? – Ingus Nov 23 '16 at 09:30
  • Also for one person in August has sick days from 2-4 and from 24-(some date in September) so there should be 9 days but it shows only 2 – Ingus Nov 23 '16 at 09:32
1

PHP DateTime Option:

    function get_days( $start, $end )
    {  
      $begin = new DateTime( $start );
      $end   = new DateTime( $end );
      //$end   = $end->modify( '+1 day' ); //add one day so as to include the end date of our range

      $total_days = 0;
    //this will calculate total days from monday to friday in above date range
      for( $i = $begin; $i <= $end; $i->modify( '+1 day' ) )
      {
        // Check that the date is between Monday and Friday and only in August
        if( ( $i->format( 'N' ) >= 1 && $i->format( 'N') <= 5 ) && $i->format( 'm' ) == '08' )
        {
          $total_days++;
        }
      }
      return $total_days;
    }

    $total = 0;
    $total += get_days( '2016-07-27', '2016-08-02');
    $total += get_days( '2016-08-08', '2016-08-10');
    $total += get_days( '2016-08-24', '2016-09-02');
Blinkydamo
  • 1,582
  • 9
  • 20
  • @IngusGraholskis Have altered it a little to be easily used for other dates. – Blinkydamo Nov 23 '16 at 08:35
  • This one seem to gram and count all dates in the period – Ingus Nov 23 '16 at 09:25
  • @IngusGraholskis If you run the code and echo out `$total` it shows 13 for the given periods. – Blinkydamo Nov 23 '16 at 09:39
  • @IngusGraholskis In fact if you remove the `$end + 1` it will show 11 which is actually the amount of days in August that you are looking for. – Blinkydamo Nov 23 '16 at 09:41
  • for one person in August has sick days from 2-4 and from 24 - (some date in September) so there should be 9 days but it shows only 3 days , like it would take first result and skip next period – Ingus Nov 24 '16 at 08:01
  • @IngusGraholskis Have a look here, the dates you are asking for shows a total of 9 days - https://eval.in/684552 – Blinkydamo Nov 24 '16 at 09:14
  • funny why it dont work when i take dates from my database??any idea? – Ingus Nov 24 '16 at 09:19
  • You more than likely need to loop through the results from the database and call the function I provided passing the dates for each range to the function. If you have a go with the new function, pass the variables you are looking at and get a result then you could start a new question with the issues you are getting with that. The question you asked here is complete and really we shouldn't be changing the content as we go. – Blinkydamo Nov 24 '16 at 09:22