Search moodle.org's
Developer Documentation

See Release Notes
Long Term Support Release

  • Bug fixes for general core bugs in 4.1.x will end 13 November 2023 (12 months).
  • Bug fixes for security issues in 4.1.x will end 10 November 2025 (36 months).
  • PHP version: minimum PHP 7.4.0 Note: minimum PHP version has increased since Moodle 4.0. PHP 8.0.x is supported too.

Differences Between: [Versions 400 and 401]

   1  <?php
   2  
   3  namespace PhpOffice\PhpSpreadsheet\Calculation\DateTimeExcel;
   4  
   5  use PhpOffice\PhpSpreadsheet\Calculation\ArrayEnabled;
   6  use PhpOffice\PhpSpreadsheet\Calculation\Exception;
   7  use PhpOffice\PhpSpreadsheet\Calculation\Functions;
   8  
   9  class NetworkDays
  10  {
  11      use ArrayEnabled;
  12  
  13      /**
  14       * NETWORKDAYS.
  15       *
  16       * Returns the number of whole working days between start_date and end_date. Working days
  17       * exclude weekends and any dates identified in holidays.
  18       * Use NETWORKDAYS to calculate employee benefits that accrue based on the number of days
  19       * worked during a specific term.
  20       *
  21       * Excel Function:
  22       *        NETWORKDAYS(startDate,endDate[,holidays[,holiday[,...]]])
  23       *
  24       * @param mixed $startDate Excel date serial value (float), PHP date timestamp (integer),
  25       *                                            PHP DateTime object, or a standard date string
  26       *                         Or can be an array of date values
  27       * @param mixed $endDate Excel date serial value (float), PHP date timestamp (integer),
  28       *                                            PHP DateTime object, or a standard date string
  29       *                         Or can be an array of date values
  30       * @param mixed $dateArgs An array of dates (such as holidays) to exclude from the calculation
  31       *
  32       * @return array|int|string Interval between the dates
  33       *         If an array of values is passed for the $startDate or $endDate arguments, then the returned result
  34       *            will also be an array with matching dimensions
  35       */
  36      public static function count($startDate, $endDate, ...$dateArgs)
  37      {
  38          if (is_array($startDate) || is_array($endDate)) {
  39              return self::evaluateArrayArgumentsSubset(
  40                  [self::class, __FUNCTION__],
  41                  2,
  42                  $startDate,
  43                  $endDate,
  44                  ...$dateArgs
  45              );
  46          }
  47  
  48          try {
  49              //    Retrieve the mandatory start and end date that are referenced in the function definition
  50              $sDate = Helpers::getDateValue($startDate);
  51              $eDate = Helpers::getDateValue($endDate);
  52              $startDate = min($sDate, $eDate);
  53              $endDate = max($sDate, $eDate);
  54              //    Get the optional days
  55              $dateArgs = Functions::flattenArray($dateArgs);
  56              //    Test any extra holiday parameters
  57              $holidayArray = [];
  58              foreach ($dateArgs as $holidayDate) {
  59                  $holidayArray[] = Helpers::getDateValue($holidayDate);
  60              }
  61          } catch (Exception $e) {
  62              return $e->getMessage();
  63          }
  64  
  65          // Execute function
  66          $startDow = self::calcStartDow($startDate);
  67          $endDow = self::calcEndDow($endDate);
  68          $wholeWeekDays = (int) floor(($endDate - $startDate) / 7) * 5;
  69          $partWeekDays = self::calcPartWeekDays($startDow, $endDow);
  70  
  71          //    Test any extra holiday parameters
  72          $holidayCountedArray = [];
  73          foreach ($holidayArray as $holidayDate) {
  74              if (($holidayDate >= $startDate) && ($holidayDate <= $endDate)) {
  75                  if ((Week::day($holidayDate, 2) < 6) && (!in_array($holidayDate, $holidayCountedArray))) {
  76                      --$partWeekDays;
  77                      $holidayCountedArray[] = $holidayDate;
  78                  }
  79              }
  80          }
  81  
  82          return self::applySign($wholeWeekDays + $partWeekDays, $sDate, $eDate);
  83      }
  84  
  85      private static function calcStartDow(float $startDate): int
  86      {
  87          $startDow = 6 - (int) Week::day($startDate, 2);
  88          if ($startDow < 0) {
  89              $startDow = 5;
  90          }
  91  
  92          return $startDow;
  93      }
  94  
  95      private static function calcEndDow(float $endDate): int
  96      {
  97          $endDow = (int) Week::day($endDate, 2);
  98          if ($endDow >= 6) {
  99              $endDow = 0;
 100          }
 101  
 102          return $endDow;
 103      }
 104  
 105      private static function calcPartWeekDays(int $startDow, int $endDow): int
 106      {
 107          $partWeekDays = $endDow + $startDow;
 108          if ($partWeekDays > 5) {
 109              $partWeekDays -= 5;
 110          }
 111  
 112          return $partWeekDays;
 113      }
 114  
 115      private static function applySign(int $result, float $sDate, float $eDate): int
 116      {
 117          return ($sDate > $eDate) ? -$result : $result;
 118      }
 119  }