[ Index ]

PHP Cross Reference of Unnamed Project

title

Body

[close]

/lib/phpexcel/PHPExcel/Calculation/ -> DateTime.php (source)

   1  <?php
   2  
   3  /** PHPExcel root directory */
   4  if (!defined('PHPEXCEL_ROOT')) {
   5      /**
   6       * @ignore
   7       */
   8      define('PHPEXCEL_ROOT', dirname(__FILE__) . '/../../');
   9      require (PHPEXCEL_ROOT . 'PHPExcel/Autoloader.php');
  10  }
  11  
  12  /**
  13   * PHPExcel_Calculation_DateTime
  14   *
  15   * Copyright (c) 2006 - 2015 PHPExcel
  16   *
  17   * This library is free software; you can redistribute it and/or
  18   * modify it under the terms of the GNU Lesser General Public
  19   * License as published by the Free Software Foundation; either
  20   * version 2.1 of the License, or (at your option) any later version.
  21   *
  22   * This library is distributed in the hope that it will be useful,
  23   * but WITHOUT ANY WARRANTY; without even the implied warranty of
  24   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  25   * Lesser General Public License for more details.
  26   *
  27   * You should have received a copy of the GNU Lesser General Public
  28   * License along with this library; if not, write to the Free Software
  29   * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  30   *
  31   * @category    PHPExcel
  32   * @package        PHPExcel_Calculation
  33   * @copyright    Copyright (c) 2006 - 2015 PHPExcel (http://www.codeplex.com/PHPExcel)
  34   * @license        http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt    LGPL
  35   * @version        ##VERSION##, ##DATE##
  36   */
  37  class PHPExcel_Calculation_DateTime
  38  {
  39      /**
  40       * Identify if a year is a leap year or not
  41       *
  42       * @param    integer    $year    The year to test
  43       * @return    boolean            TRUE if the year is a leap year, otherwise FALSE
  44       */
  45      public static function isLeapYear($year)
  46      {
  47          return ((($year % 4) == 0) && (($year % 100) != 0) || (($year % 400) == 0));
  48      }
  49  
  50  
  51      /**
  52       * Return the number of days between two dates based on a 360 day calendar
  53       *
  54       * @param    integer    $startDay        Day of month of the start date
  55       * @param    integer    $startMonth        Month of the start date
  56       * @param    integer    $startYear        Year of the start date
  57       * @param    integer    $endDay            Day of month of the start date
  58       * @param    integer    $endMonth        Month of the start date
  59       * @param    integer    $endYear        Year of the start date
  60       * @param    boolean $methodUS        Whether to use the US method or the European method of calculation
  61       * @return    integer    Number of days between the start date and the end date
  62       */
  63      private static function dateDiff360($startDay, $startMonth, $startYear, $endDay, $endMonth, $endYear, $methodUS)
  64      {
  65          if ($startDay == 31) {
  66              --$startDay;
  67          } elseif ($methodUS && ($startMonth == 2 && ($startDay == 29 || ($startDay == 28 && !self::isLeapYear($startYear))))) {
  68              $startDay = 30;
  69          }
  70          if ($endDay == 31) {
  71              if ($methodUS && $startDay != 30) {
  72                  $endDay = 1;
  73                  if ($endMonth == 12) {
  74                      ++$endYear;
  75                      $endMonth = 1;
  76                  } else {
  77                      ++$endMonth;
  78                  }
  79              } else {
  80                  $endDay = 30;
  81              }
  82          }
  83  
  84          return $endDay + $endMonth * 30 + $endYear * 360 - $startDay - $startMonth * 30 - $startYear * 360;
  85      }
  86  
  87  
  88      /**
  89       * getDateValue
  90       *
  91       * @param    string    $dateValue
  92       * @return    mixed    Excel date/time serial value, or string if error
  93       */
  94      public static function getDateValue($dateValue)
  95      {
  96          if (!is_numeric($dateValue)) {
  97              if ((is_string($dateValue)) &&
  98                  (PHPExcel_Calculation_Functions::getCompatibilityMode() == PHPExcel_Calculation_Functions::COMPATIBILITY_GNUMERIC)) {
  99                  return PHPExcel_Calculation_Functions::VALUE();
 100              }
 101              if ((is_object($dateValue)) && ($dateValue instanceof DateTime)) {
 102                  $dateValue = PHPExcel_Shared_Date::PHPToExcel($dateValue);
 103              } else {
 104                  $saveReturnDateType = PHPExcel_Calculation_Functions::getReturnDateType();
 105                  PHPExcel_Calculation_Functions::setReturnDateType(PHPExcel_Calculation_Functions::RETURNDATE_EXCEL);
 106                  $dateValue = self::DATEVALUE($dateValue);
 107                  PHPExcel_Calculation_Functions::setReturnDateType($saveReturnDateType);
 108              }
 109          }
 110          return $dateValue;
 111      }
 112  
 113  
 114      /**
 115       * getTimeValue
 116       *
 117       * @param    string    $timeValue
 118       * @return    mixed    Excel date/time serial value, or string if error
 119       */
 120      private static function getTimeValue($timeValue)
 121      {
 122          $saveReturnDateType = PHPExcel_Calculation_Functions::getReturnDateType();
 123          PHPExcel_Calculation_Functions::setReturnDateType(PHPExcel_Calculation_Functions::RETURNDATE_EXCEL);
 124          $timeValue = self::TIMEVALUE($timeValue);
 125          PHPExcel_Calculation_Functions::setReturnDateType($saveReturnDateType);
 126          return $timeValue;
 127      }
 128  
 129  
 130      private static function adjustDateByMonths($dateValue = 0, $adjustmentMonths = 0)
 131      {
 132          // Execute function
 133          $PHPDateObject = PHPExcel_Shared_Date::ExcelToPHPObject($dateValue);
 134          $oMonth = (int) $PHPDateObject->format('m');
 135          $oYear = (int) $PHPDateObject->format('Y');
 136  
 137          $adjustmentMonthsString = (string) $adjustmentMonths;
 138          if ($adjustmentMonths > 0) {
 139              $adjustmentMonthsString = '+'.$adjustmentMonths;
 140          }
 141          if ($adjustmentMonths != 0) {
 142              $PHPDateObject->modify($adjustmentMonthsString.' months');
 143          }
 144          $nMonth = (int) $PHPDateObject->format('m');
 145          $nYear = (int) $PHPDateObject->format('Y');
 146  
 147          $monthDiff = ($nMonth - $oMonth) + (($nYear - $oYear) * 12);
 148          if ($monthDiff != $adjustmentMonths) {
 149              $adjustDays = (int) $PHPDateObject->format('d');
 150              $adjustDaysString = '-'.$adjustDays.' days';
 151              $PHPDateObject->modify($adjustDaysString);
 152          }
 153          return $PHPDateObject;
 154      }
 155  
 156  
 157      /**
 158       * DATETIMENOW
 159       *
 160       * Returns the current date and time.
 161       * The NOW function is useful when you need to display the current date and time on a worksheet or
 162       * calculate a value based on the current date and time, and have that value updated each time you
 163       * open the worksheet.
 164       *
 165       * NOTE: When used in a Cell Formula, MS Excel changes the cell format so that it matches the date
 166       * and time format of your regional settings. PHPExcel does not change cell formatting in this way.
 167       *
 168       * Excel Function:
 169       *        NOW()
 170       *
 171       * @access    public
 172       * @category Date/Time Functions
 173       * @return    mixed    Excel date/time serial value, PHP date/time serial value or PHP date/time object,
 174       *                        depending on the value of the ReturnDateType flag
 175       */
 176      public static function DATETIMENOW()
 177      {
 178          $saveTimeZone = date_default_timezone_get();
 179          date_default_timezone_set('UTC');
 180          $retValue = false;
 181          switch (PHPExcel_Calculation_Functions::getReturnDateType()) {
 182              case PHPExcel_Calculation_Functions::RETURNDATE_EXCEL:
 183                  $retValue = (float) PHPExcel_Shared_Date::PHPToExcel(time());
 184                  break;
 185              case PHPExcel_Calculation_Functions::RETURNDATE_PHP_NUMERIC:
 186                  $retValue = (integer) time();
 187                  break;
 188              case PHPExcel_Calculation_Functions::RETURNDATE_PHP_OBJECT:
 189                  $retValue = new DateTime();
 190                  break;
 191          }
 192          date_default_timezone_set($saveTimeZone);
 193  
 194          return $retValue;
 195      }
 196  
 197  
 198      /**
 199       * DATENOW
 200       *
 201       * Returns the current date.
 202       * The NOW function is useful when you need to display the current date and time on a worksheet or
 203       * calculate a value based on the current date and time, and have that value updated each time you
 204       * open the worksheet.
 205       *
 206       * NOTE: When used in a Cell Formula, MS Excel changes the cell format so that it matches the date
 207       * and time format of your regional settings. PHPExcel does not change cell formatting in this way.
 208       *
 209       * Excel Function:
 210       *        TODAY()
 211       *
 212       * @access    public
 213       * @category Date/Time Functions
 214       * @return    mixed    Excel date/time serial value, PHP date/time serial value or PHP date/time object,
 215       *                        depending on the value of the ReturnDateType flag
 216       */
 217      public static function DATENOW()
 218      {
 219          $saveTimeZone = date_default_timezone_get();
 220          date_default_timezone_set('UTC');
 221          $retValue = false;
 222          $excelDateTime = floor(PHPExcel_Shared_Date::PHPToExcel(time()));
 223          switch (PHPExcel_Calculation_Functions::getReturnDateType()) {
 224              case PHPExcel_Calculation_Functions::RETURNDATE_EXCEL:
 225                  $retValue = (float) $excelDateTime;
 226                  break;
 227              case PHPExcel_Calculation_Functions::RETURNDATE_PHP_NUMERIC:
 228                  $retValue = (integer) PHPExcel_Shared_Date::ExcelToPHP($excelDateTime);
 229                  break;
 230              case PHPExcel_Calculation_Functions::RETURNDATE_PHP_OBJECT:
 231                  $retValue = PHPExcel_Shared_Date::ExcelToPHPObject($excelDateTime);
 232                  break;
 233          }
 234          date_default_timezone_set($saveTimeZone);
 235  
 236          return $retValue;
 237      }
 238  
 239  
 240      /**
 241       * DATE
 242       *
 243       * The DATE function returns a value that represents a particular date.
 244       *
 245       * NOTE: When used in a Cell Formula, MS Excel changes the cell format so that it matches the date
 246       * format of your regional settings. PHPExcel does not change cell formatting in this way.
 247       *
 248       * Excel Function:
 249       *        DATE(year,month,day)
 250       *
 251       * PHPExcel is a lot more forgiving than MS Excel when passing non numeric values to this function.
 252       * A Month name or abbreviation (English only at this point) such as 'January' or 'Jan' will still be accepted,
 253       *     as will a day value with a suffix (e.g. '21st' rather than simply 21); again only English language.
 254       *
 255       * @access    public
 256       * @category Date/Time Functions
 257       * @param    integer        $year    The value of the year argument can include one to four digits.
 258       *                                Excel interprets the year argument according to the configured
 259       *                                date system: 1900 or 1904.
 260       *                                If year is between 0 (zero) and 1899 (inclusive), Excel adds that
 261       *                                value to 1900 to calculate the year. For example, DATE(108,1,2)
 262       *                                returns January 2, 2008 (1900+108).
 263       *                                If year is between 1900 and 9999 (inclusive), Excel uses that
 264       *                                value as the year. For example, DATE(2008,1,2) returns January 2,
 265       *                                2008.
 266       *                                If year is less than 0 or is 10000 or greater, Excel returns the
 267       *                                #NUM! error value.
 268       * @param    integer        $month    A positive or negative integer representing the month of the year
 269       *                                from 1 to 12 (January to December).
 270       *                                If month is greater than 12, month adds that number of months to
 271       *                                the first month in the year specified. For example, DATE(2008,14,2)
 272       *                                returns the serial number representing February 2, 2009.
 273       *                                If month is less than 1, month subtracts the magnitude of that
 274       *                                number of months, plus 1, from the first month in the year
 275       *                                specified. For example, DATE(2008,-3,2) returns the serial number
 276       *                                representing September 2, 2007.
 277       * @param    integer        $day    A positive or negative integer representing the day of the month
 278       *                                from 1 to 31.
 279       *                                If day is greater than the number of days in the month specified,
 280       *                                day adds that number of days to the first day in the month. For
 281       *                                example, DATE(2008,1,35) returns the serial number representing
 282       *                                February 4, 2008.
 283       *                                If day is less than 1, day subtracts the magnitude that number of
 284       *                                days, plus one, from the first day of the month specified. For
 285       *                                example, DATE(2008,1,-15) returns the serial number representing
 286       *                                December 16, 2007.
 287       * @return    mixed    Excel date/time serial value, PHP date/time serial value or PHP date/time object,
 288       *                        depending on the value of the ReturnDateType flag
 289       */
 290      public static function DATE($year = 0, $month = 1, $day = 1)
 291      {
 292          $year  = PHPExcel_Calculation_Functions::flattenSingleValue($year);
 293          $month = PHPExcel_Calculation_Functions::flattenSingleValue($month);
 294          $day   = PHPExcel_Calculation_Functions::flattenSingleValue($day);
 295  
 296          if (($month !== null) && (!is_numeric($month))) {
 297              $month = PHPExcel_Shared_Date::monthStringToNumber($month);
 298          }
 299  
 300          if (($day !== null) && (!is_numeric($day))) {
 301              $day = PHPExcel_Shared_Date::dayStringToNumber($day);
 302          }
 303  
 304          $year = ($year !== null) ? PHPExcel_Shared_String::testStringAsNumeric($year) : 0;
 305          $month = ($month !== null) ? PHPExcel_Shared_String::testStringAsNumeric($month) : 0;
 306          $day = ($day !== null) ? PHPExcel_Shared_String::testStringAsNumeric($day) : 0;
 307          if ((!is_numeric($year)) ||
 308              (!is_numeric($month)) ||
 309              (!is_numeric($day))) {
 310              return PHPExcel_Calculation_Functions::VALUE();
 311          }
 312          $year    = (integer) $year;
 313          $month    = (integer) $month;
 314          $day    = (integer) $day;
 315  
 316          $baseYear = PHPExcel_Shared_Date::getExcelCalendar();
 317          // Validate parameters
 318          if ($year < ($baseYear-1900)) {
 319              return PHPExcel_Calculation_Functions::NaN();
 320          }
 321          if ((($baseYear-1900) != 0) && ($year < $baseYear) && ($year >= 1900)) {
 322              return PHPExcel_Calculation_Functions::NaN();
 323          }
 324  
 325          if (($year < $baseYear) && ($year >= ($baseYear-1900))) {
 326              $year += 1900;
 327          }
 328  
 329          if ($month < 1) {
 330              //    Handle year/month adjustment if month < 1
 331              --$month;
 332              $year += ceil($month / 12) - 1;
 333              $month = 13 - abs($month % 12);
 334          } elseif ($month > 12) {
 335              //    Handle year/month adjustment if month > 12
 336              $year += floor($month / 12);
 337              $month = ($month % 12);
 338          }
 339  
 340          // Re-validate the year parameter after adjustments
 341          if (($year < $baseYear) || ($year >= 10000)) {
 342              return PHPExcel_Calculation_Functions::NaN();
 343          }
 344  
 345          // Execute function
 346          $excelDateValue = PHPExcel_Shared_Date::FormattedPHPToExcel($year, $month, $day);
 347          switch (PHPExcel_Calculation_Functions::getReturnDateType()) {
 348              case PHPExcel_Calculation_Functions::RETURNDATE_EXCEL:
 349                  return (float) $excelDateValue;
 350              case PHPExcel_Calculation_Functions::RETURNDATE_PHP_NUMERIC:
 351                  return (integer) PHPExcel_Shared_Date::ExcelToPHP($excelDateValue);
 352              case PHPExcel_Calculation_Functions::RETURNDATE_PHP_OBJECT:
 353                  return PHPExcel_Shared_Date::ExcelToPHPObject($excelDateValue);
 354          }
 355      }
 356  
 357  
 358      /**
 359       * TIME
 360       *
 361       * The TIME function returns a value that represents a particular time.
 362       *
 363       * NOTE: When used in a Cell Formula, MS Excel changes the cell format so that it matches the time
 364       * format of your regional settings. PHPExcel does not change cell formatting in this way.
 365       *
 366       * Excel Function:
 367       *        TIME(hour,minute,second)
 368       *
 369       * @access    public
 370       * @category Date/Time Functions
 371       * @param    integer        $hour        A number from 0 (zero) to 32767 representing the hour.
 372       *                                    Any value greater than 23 will be divided by 24 and the remainder
 373       *                                    will be treated as the hour value. For example, TIME(27,0,0) =
 374       *                                    TIME(3,0,0) = .125 or 3:00 AM.
 375       * @param    integer        $minute        A number from 0 to 32767 representing the minute.
 376       *                                    Any value greater than 59 will be converted to hours and minutes.
 377       *                                    For example, TIME(0,750,0) = TIME(12,30,0) = .520833 or 12:30 PM.
 378       * @param    integer        $second        A number from 0 to 32767 representing the second.
 379       *                                    Any value greater than 59 will be converted to hours, minutes,
 380       *                                    and seconds. For example, TIME(0,0,2000) = TIME(0,33,22) = .023148
 381       *                                    or 12:33:20 AM
 382       * @return    mixed    Excel date/time serial value, PHP date/time serial value or PHP date/time object,
 383       *                        depending on the value of the ReturnDateType flag
 384       */
 385      public static function TIME($hour = 0, $minute = 0, $second = 0)
 386      {
 387          $hour = PHPExcel_Calculation_Functions::flattenSingleValue($hour);
 388          $minute = PHPExcel_Calculation_Functions::flattenSingleValue($minute);
 389          $second = PHPExcel_Calculation_Functions::flattenSingleValue($second);
 390  
 391          if ($hour == '') {
 392              $hour = 0;
 393          }
 394          if ($minute == '') {
 395              $minute = 0;
 396          }
 397          if ($second == '') {
 398              $second = 0;
 399          }
 400  
 401          if ((!is_numeric($hour)) || (!is_numeric($minute)) || (!is_numeric($second))) {
 402              return PHPExcel_Calculation_Functions::VALUE();
 403          }
 404          $hour = (integer) $hour;
 405          $minute = (integer) $minute;
 406          $second = (integer) $second;
 407  
 408          if ($second < 0) {
 409              $minute += floor($second / 60);
 410              $second = 60 - abs($second % 60);
 411              if ($second == 60) {
 412                  $second = 0;
 413              }
 414          } elseif ($second >= 60) {
 415              $minute += floor($second / 60);
 416              $second = $second % 60;
 417          }
 418          if ($minute < 0) {
 419              $hour += floor($minute / 60);
 420              $minute = 60 - abs($minute % 60);
 421              if ($minute == 60) {
 422                  $minute = 0;
 423              }
 424          } elseif ($minute >= 60) {
 425              $hour += floor($minute / 60);
 426              $minute = $minute % 60;
 427          }
 428  
 429          if ($hour > 23) {
 430              $hour = $hour % 24;
 431          } elseif ($hour < 0) {
 432              return PHPExcel_Calculation_Functions::NaN();
 433          }
 434  
 435          // Execute function
 436          switch (PHPExcel_Calculation_Functions::getReturnDateType()) {
 437              case PHPExcel_Calculation_Functions::RETURNDATE_EXCEL:
 438                  $date = 0;
 439                  $calendar = PHPExcel_Shared_Date::getExcelCalendar();
 440                  if ($calendar != PHPExcel_Shared_Date::CALENDAR_WINDOWS_1900) {
 441                      $date = 1;
 442                  }
 443                  return (float) PHPExcel_Shared_Date::FormattedPHPToExcel($calendar, 1, $date, $hour, $minute, $second);
 444              case PHPExcel_Calculation_Functions::RETURNDATE_PHP_NUMERIC:
 445                  return (integer) PHPExcel_Shared_Date::ExcelToPHP(PHPExcel_Shared_Date::FormattedPHPToExcel(1970, 1, 1, $hour, $minute, $second));    // -2147468400; //    -2147472000 + 3600
 446              case PHPExcel_Calculation_Functions::RETURNDATE_PHP_OBJECT:
 447                  $dayAdjust = 0;
 448                  if ($hour < 0) {
 449                      $dayAdjust = floor($hour / 24);
 450                      $hour = 24 - abs($hour % 24);
 451                      if ($hour == 24) {
 452                          $hour = 0;
 453                      }
 454                  } elseif ($hour >= 24) {
 455                      $dayAdjust = floor($hour / 24);
 456                      $hour = $hour % 24;
 457                  }
 458                  $phpDateObject = new DateTime('1900-01-01 '.$hour.':'.$minute.':'.$second);
 459                  if ($dayAdjust != 0) {
 460                      $phpDateObject->modify($dayAdjust.' days');
 461                  }
 462                  return $phpDateObject;
 463          }
 464      }
 465  
 466  
 467      /**
 468       * DATEVALUE
 469       *
 470       * Returns a value that represents a particular date.
 471       * Use DATEVALUE to convert a date represented by a text string to an Excel or PHP date/time stamp
 472       * value.
 473       *
 474       * NOTE: When used in a Cell Formula, MS Excel changes the cell format so that it matches the date
 475       * format of your regional settings. PHPExcel does not change cell formatting in this way.
 476       *
 477       * Excel Function:
 478       *        DATEVALUE(dateValue)
 479       *
 480       * @access    public
 481       * @category Date/Time Functions
 482       * @param    string    $dateValue        Text that represents a date in a Microsoft Excel date format.
 483       *                                    For example, "1/30/2008" or "30-Jan-2008" are text strings within
 484       *                                    quotation marks that represent dates. Using the default date
 485       *                                    system in Excel for Windows, date_text must represent a date from
 486       *                                    January 1, 1900, to December 31, 9999. Using the default date
 487       *                                    system in Excel for the Macintosh, date_text must represent a date
 488       *                                    from January 1, 1904, to December 31, 9999. DATEVALUE returns the
 489       *                                    #VALUE! error value if date_text is out of this range.
 490       * @return    mixed    Excel date/time serial value, PHP date/time serial value or PHP date/time object,
 491       *                        depending on the value of the ReturnDateType flag
 492       */
 493      public static function DATEVALUE($dateValue = 1)
 494      {
 495          $dateValue = trim(PHPExcel_Calculation_Functions::flattenSingleValue($dateValue), '"');
 496          //    Strip any ordinals because they're allowed in Excel (English only)
 497          $dateValue = preg_replace('/(\d)(st|nd|rd|th)([ -\/])/Ui', '$1$3', $dateValue);
 498          //    Convert separators (/ . or space) to hyphens (should also handle dot used for ordinals in some countries, e.g. Denmark, Germany)
 499          $dateValue    = str_replace(array('/', '.', '-', '  '), array(' ', ' ', ' ', ' '), $dateValue);
 500  
 501          $yearFound = false;
 502          $t1 = explode(' ', $dateValue);
 503          foreach ($t1 as &$t) {
 504              if ((is_numeric($t)) && ($t > 31)) {
 505                  if ($yearFound) {
 506                      return PHPExcel_Calculation_Functions::VALUE();
 507                  } else {
 508                      if ($t < 100) {
 509                          $t += 1900;
 510                      }
 511                      $yearFound = true;
 512                  }
 513              }
 514          }
 515          if ((count($t1) == 1) && (strpos($t, ':') != false)) {
 516              //    We've been fed a time value without any date
 517              return 0.0;
 518          } elseif (count($t1) == 2) {
 519              //    We only have two parts of the date: either day/month or month/year
 520              if ($yearFound) {
 521                  array_unshift($t1, 1);
 522              } else {
 523                  array_push($t1, date('Y'));
 524              }
 525          }
 526          unset($t);
 527          $dateValue = implode(' ', $t1);
 528  
 529          $PHPDateArray = date_parse($dateValue);
 530          if (($PHPDateArray === false) || ($PHPDateArray['error_count'] > 0)) {
 531              $testVal1 = strtok($dateValue, '- ');
 532              if ($testVal1 !== false) {
 533                  $testVal2 = strtok('- ');
 534                  if ($testVal2 !== false) {
 535                      $testVal3 = strtok('- ');
 536                      if ($testVal3 === false) {
 537                          $testVal3 = strftime('%Y');
 538                      }
 539                  } else {
 540                      return PHPExcel_Calculation_Functions::VALUE();
 541                  }
 542              } else {
 543                  return PHPExcel_Calculation_Functions::VALUE();
 544              }
 545              $PHPDateArray = date_parse($testVal1.'-'.$testVal2.'-'.$testVal3);
 546              if (($PHPDateArray === false) || ($PHPDateArray['error_count'] > 0)) {
 547                  $PHPDateArray = date_parse($testVal2.'-'.$testVal1.'-'.$testVal3);
 548                  if (($PHPDateArray === false) || ($PHPDateArray['error_count'] > 0)) {
 549                      return PHPExcel_Calculation_Functions::VALUE();
 550                  }
 551              }
 552          }
 553  
 554          if (($PHPDateArray !== false) && ($PHPDateArray['error_count'] == 0)) {
 555              // Execute function
 556              if ($PHPDateArray['year'] == '') {
 557                  $PHPDateArray['year'] = strftime('%Y');
 558              }
 559              if ($PHPDateArray['year'] < 1900) {
 560                  return PHPExcel_Calculation_Functions::VALUE();
 561              }
 562              if ($PHPDateArray['month'] == '') {
 563                  $PHPDateArray['month'] = strftime('%m');
 564              }
 565              if ($PHPDateArray['day'] == '') {
 566                  $PHPDateArray['day'] = strftime('%d');
 567              }
 568              $excelDateValue = floor(
 569                  PHPExcel_Shared_Date::FormattedPHPToExcel(
 570                      $PHPDateArray['year'],
 571                      $PHPDateArray['month'],
 572                      $PHPDateArray['day'],
 573                      $PHPDateArray['hour'],
 574                      $PHPDateArray['minute'],
 575                      $PHPDateArray['second']
 576                  )
 577              );
 578  
 579              switch (PHPExcel_Calculation_Functions::getReturnDateType()) {
 580                  case PHPExcel_Calculation_Functions::RETURNDATE_EXCEL:
 581                      return (float) $excelDateValue;
 582                  case PHPExcel_Calculation_Functions::RETURNDATE_PHP_NUMERIC:
 583                      return (integer) PHPExcel_Shared_Date::ExcelToPHP($excelDateValue);
 584                  case PHPExcel_Calculation_Functions::RETURNDATE_PHP_OBJECT:
 585                      return new DateTime($PHPDateArray['year'].'-'.$PHPDateArray['month'].'-'.$PHPDateArray['day'].' 00:00:00');
 586              }
 587          }
 588          return PHPExcel_Calculation_Functions::VALUE();
 589      }
 590  
 591  
 592      /**
 593       * TIMEVALUE
 594       *
 595       * Returns a value that represents a particular time.
 596       * Use TIMEVALUE to convert a time represented by a text string to an Excel or PHP date/time stamp
 597       * value.
 598       *
 599       * NOTE: When used in a Cell Formula, MS Excel changes the cell format so that it matches the time
 600       * format of your regional settings. PHPExcel does not change cell formatting in this way.
 601       *
 602       * Excel Function:
 603       *        TIMEVALUE(timeValue)
 604       *
 605       * @access    public
 606       * @category Date/Time Functions
 607       * @param    string    $timeValue        A text string that represents a time in any one of the Microsoft
 608       *                                    Excel time formats; for example, "6:45 PM" and "18:45" text strings
 609       *                                    within quotation marks that represent time.
 610       *                                    Date information in time_text is ignored.
 611       * @return    mixed    Excel date/time serial value, PHP date/time serial value or PHP date/time object,
 612       *                        depending on the value of the ReturnDateType flag
 613       */
 614      public static function TIMEVALUE($timeValue)
 615      {
 616          $timeValue = trim(PHPExcel_Calculation_Functions::flattenSingleValue($timeValue), '"');
 617          $timeValue = str_replace(array('/', '.'), array('-', '-'), $timeValue);
 618  
 619          $PHPDateArray = date_parse($timeValue);
 620          if (($PHPDateArray !== false) && ($PHPDateArray['error_count'] == 0)) {
 621              if (PHPExcel_Calculation_Functions::getCompatibilityMode() == PHPExcel_Calculation_Functions::COMPATIBILITY_OPENOFFICE) {
 622                  $excelDateValue = PHPExcel_Shared_Date::FormattedPHPToExcel(
 623                      $PHPDateArray['year'],
 624                      $PHPDateArray['month'],
 625                      $PHPDateArray['day'],
 626                      $PHPDateArray['hour'],
 627                      $PHPDateArray['minute'],
 628                      $PHPDateArray['second']
 629                  );
 630              } else {
 631                  $excelDateValue = PHPExcel_Shared_Date::FormattedPHPToExcel(1900, 1, 1, $PHPDateArray['hour'], $PHPDateArray['minute'], $PHPDateArray['second']) - 1;
 632              }
 633  
 634              switch (PHPExcel_Calculation_Functions::getReturnDateType()) {
 635                  case PHPExcel_Calculation_Functions::RETURNDATE_EXCEL:
 636                      return (float) $excelDateValue;
 637                  case PHPExcel_Calculation_Functions::RETURNDATE_PHP_NUMERIC:
 638                      return (integer) $phpDateValue = PHPExcel_Shared_Date::ExcelToPHP($excelDateValue+25569) - 3600;
 639                  case PHPExcel_Calculation_Functions::RETURNDATE_PHP_OBJECT:
 640                      return new DateTime('1900-01-01 '.$PHPDateArray['hour'].':'.$PHPDateArray['minute'].':'.$PHPDateArray['second']);
 641              }
 642          }
 643          return PHPExcel_Calculation_Functions::VALUE();
 644      }
 645  
 646  
 647      /**
 648       * DATEDIF
 649       *
 650       * @param    mixed    $startDate        Excel date serial value, PHP date/time stamp, PHP DateTime object
 651       *                                    or a standard date string
 652       * @param    mixed    $endDate        Excel date serial value, PHP date/time stamp, PHP DateTime object
 653       *                                    or a standard date string
 654       * @param    string    $unit
 655       * @return    integer    Interval between the dates
 656       */
 657      public static function DATEDIF($startDate = 0, $endDate = 0, $unit = 'D')
 658      {
 659          $startDate = PHPExcel_Calculation_Functions::flattenSingleValue($startDate);
 660          $endDate   = PHPExcel_Calculation_Functions::flattenSingleValue($endDate);
 661          $unit      = strtoupper(PHPExcel_Calculation_Functions::flattenSingleValue($unit));
 662  
 663          if (is_string($startDate = self::getDateValue($startDate))) {
 664              return PHPExcel_Calculation_Functions::VALUE();
 665          }
 666          if (is_string($endDate = self::getDateValue($endDate))) {
 667              return PHPExcel_Calculation_Functions::VALUE();
 668          }
 669  
 670          // Validate parameters
 671          if ($startDate >= $endDate) {
 672              return PHPExcel_Calculation_Functions::NaN();
 673          }
 674  
 675          // Execute function
 676          $difference = $endDate - $startDate;
 677  
 678          $PHPStartDateObject = PHPExcel_Shared_Date::ExcelToPHPObject($startDate);
 679          $startDays = $PHPStartDateObject->format('j');
 680          $startMonths = $PHPStartDateObject->format('n');
 681          $startYears = $PHPStartDateObject->format('Y');
 682  
 683          $PHPEndDateObject = PHPExcel_Shared_Date::ExcelToPHPObject($endDate);
 684          $endDays = $PHPEndDateObject->format('j');
 685          $endMonths = $PHPEndDateObject->format('n');
 686          $endYears = $PHPEndDateObject->format('Y');
 687  
 688          $retVal = PHPExcel_Calculation_Functions::NaN();
 689          switch ($unit) {
 690              case 'D':
 691                  $retVal = intval($difference);
 692                  break;
 693              case 'M':
 694                  $retVal = intval($endMonths - $startMonths) + (intval($endYears - $startYears) * 12);
 695                  //    We're only interested in full months
 696                  if ($endDays < $startDays) {
 697                      --$retVal;
 698                  }
 699                  break;
 700              case 'Y':
 701                  $retVal = intval($endYears - $startYears);
 702                  //    We're only interested in full months
 703                  if ($endMonths < $startMonths) {
 704                      --$retVal;
 705                  } elseif (($endMonths == $startMonths) && ($endDays < $startDays)) {
 706                      --$retVal;
 707                  }
 708                  break;
 709              case 'MD':
 710                  if ($endDays < $startDays) {
 711                      $retVal = $endDays;
 712                      $PHPEndDateObject->modify('-'.$endDays.' days');
 713                      $adjustDays = $PHPEndDateObject->format('j');
 714                      if ($adjustDays > $startDays) {
 715                          $retVal += ($adjustDays - $startDays);
 716                      }
 717                  } else {
 718                      $retVal = $endDays - $startDays;
 719                  }
 720                  break;
 721              case 'YM':
 722                  $retVal = intval($endMonths - $startMonths);
 723                  if ($retVal < 0) {
 724                      $retVal += 12;
 725                  }
 726                  //    We're only interested in full months
 727                  if ($endDays < $startDays) {
 728                      --$retVal;
 729                  }
 730                  break;
 731              case 'YD':
 732                  $retVal = intval($difference);
 733                  if ($endYears > $startYears) {
 734                      while ($endYears > $startYears) {
 735                          $PHPEndDateObject->modify('-1 year');
 736                          $endYears = $PHPEndDateObject->format('Y');
 737                      }
 738                      $retVal = $PHPEndDateObject->format('z') - $PHPStartDateObject->format('z');
 739                      if ($retVal < 0) {
 740                          $retVal += 365;
 741                      }
 742                  }
 743                  break;
 744              default:
 745                  $retVal = PHPExcel_Calculation_Functions::NaN();
 746          }
 747          return $retVal;
 748      }
 749  
 750  
 751      /**
 752       * DAYS360
 753       *
 754       * Returns the number of days between two dates based on a 360-day year (twelve 30-day months),
 755       * which is used in some accounting calculations. Use this function to help compute payments if
 756       * your accounting system is based on twelve 30-day months.
 757       *
 758       * Excel Function:
 759       *        DAYS360(startDate,endDate[,method])
 760       *
 761       * @access    public
 762       * @category Date/Time Functions
 763       * @param    mixed        $startDate        Excel date serial value (float), PHP date timestamp (integer),
 764       *                                        PHP DateTime object, or a standard date string
 765       * @param    mixed        $endDate        Excel date serial value (float), PHP date timestamp (integer),
 766       *                                        PHP DateTime object, or a standard date string
 767       * @param    boolean        $method            US or European Method
 768       *                                        FALSE or omitted: U.S. (NASD) method. If the starting date is
 769       *                                        the last day of a month, it becomes equal to the 30th of the
 770       *                                        same month. If the ending date is the last day of a month and
 771       *                                        the starting date is earlier than the 30th of a month, the
 772       *                                        ending date becomes equal to the 1st of the next month;
 773       *                                        otherwise the ending date becomes equal to the 30th of the
 774       *                                        same month.
 775       *                                        TRUE: European method. Starting dates and ending dates that
 776       *                                        occur on the 31st of a month become equal to the 30th of the
 777       *                                        same month.
 778       * @return    integer        Number of days between start date and end date
 779       */
 780      public static function DAYS360($startDate = 0, $endDate = 0, $method = false)
 781      {
 782          $startDate    = PHPExcel_Calculation_Functions::flattenSingleValue($startDate);
 783          $endDate    = PHPExcel_Calculation_Functions::flattenSingleValue($endDate);
 784  
 785          if (is_string($startDate = self::getDateValue($startDate))) {
 786              return PHPExcel_Calculation_Functions::VALUE();
 787          }
 788          if (is_string($endDate = self::getDateValue($endDate))) {
 789              return PHPExcel_Calculation_Functions::VALUE();
 790          }
 791  
 792          if (!is_bool($method)) {
 793              return PHPExcel_Calculation_Functions::VALUE();
 794          }
 795  
 796          // Execute function
 797          $PHPStartDateObject = PHPExcel_Shared_Date::ExcelToPHPObject($startDate);
 798          $startDay = $PHPStartDateObject->format('j');
 799          $startMonth = $PHPStartDateObject->format('n');
 800          $startYear = $PHPStartDateObject->format('Y');
 801  
 802          $PHPEndDateObject = PHPExcel_Shared_Date::ExcelToPHPObject($endDate);
 803          $endDay = $PHPEndDateObject->format('j');
 804          $endMonth = $PHPEndDateObject->format('n');
 805          $endYear = $PHPEndDateObject->format('Y');
 806  
 807          return self::dateDiff360($startDay, $startMonth, $startYear, $endDay, $endMonth, $endYear, !$method);
 808      }
 809  
 810  
 811      /**
 812       * YEARFRAC
 813       *
 814       * Calculates the fraction of the year represented by the number of whole days between two dates
 815       * (the start_date and the end_date).
 816       * Use the YEARFRAC worksheet function to identify the proportion of a whole year's benefits or
 817       * obligations to assign to a specific term.
 818       *
 819       * Excel Function:
 820       *        YEARFRAC(startDate,endDate[,method])
 821       *
 822       * @access    public
 823       * @category Date/Time Functions
 824       * @param    mixed    $startDate        Excel date serial value (float), PHP date timestamp (integer),
 825       *                                    PHP DateTime object, or a standard date string
 826       * @param    mixed    $endDate        Excel date serial value (float), PHP date timestamp (integer),
 827       *                                    PHP DateTime object, or a standard date string
 828       * @param    integer    $method            Method used for the calculation
 829       *                                        0 or omitted    US (NASD) 30/360
 830       *                                        1                Actual/actual
 831       *                                        2                Actual/360
 832       *                                        3                Actual/365
 833       *                                        4                European 30/360
 834       * @return    float    fraction of the year
 835       */
 836      public static function YEARFRAC($startDate = 0, $endDate = 0, $method = 0)
 837      {
 838          $startDate    = PHPExcel_Calculation_Functions::flattenSingleValue($startDate);
 839          $endDate    = PHPExcel_Calculation_Functions::flattenSingleValue($endDate);
 840          $method        = PHPExcel_Calculation_Functions::flattenSingleValue($method);
 841  
 842          if (is_string($startDate = self::getDateValue($startDate))) {
 843              return PHPExcel_Calculation_Functions::VALUE();
 844          }
 845          if (is_string($endDate = self::getDateValue($endDate))) {
 846              return PHPExcel_Calculation_Functions::VALUE();
 847          }
 848  
 849          if (((is_numeric($method)) && (!is_string($method))) || ($method == '')) {
 850              switch ($method) {
 851                  case 0:
 852                      return self::DAYS360($startDate, $endDate) / 360;
 853                  case 1:
 854                      $days = self::DATEDIF($startDate, $endDate);
 855                      $startYear = self::YEAR($startDate);
 856                      $endYear = self::YEAR($endDate);
 857                      $years = $endYear - $startYear + 1;
 858                      $leapDays = 0;
 859                      if ($years == 1) {
 860                          if (self::isLeapYear($endYear)) {
 861                              $startMonth = self::MONTHOFYEAR($startDate);
 862                              $endMonth = self::MONTHOFYEAR($endDate);
 863                              $endDay = self::DAYOFMONTH($endDate);
 864                              if (($startMonth < 3) ||
 865                                  (($endMonth * 100 + $endDay) >= (2 * 100 + 29))) {
 866                                   $leapDays += 1;
 867                              }
 868                          }
 869                      } else {
 870                          for ($year = $startYear; $year <= $endYear; ++$year) {
 871                              if ($year == $startYear) {
 872                                  $startMonth = self::MONTHOFYEAR($startDate);
 873                                  $startDay = self::DAYOFMONTH($startDate);
 874                                  if ($startMonth < 3) {
 875                                      $leapDays += (self::isLeapYear($year)) ? 1 : 0;
 876                                  }
 877                              } elseif ($year == $endYear) {
 878                                  $endMonth = self::MONTHOFYEAR($endDate);
 879                                  $endDay = self::DAYOFMONTH($endDate);
 880                                  if (($endMonth * 100 + $endDay) >= (2 * 100 + 29)) {
 881                                      $leapDays += (self::isLeapYear($year)) ? 1 : 0;
 882                                  }
 883                              } else {
 884                                  $leapDays += (self::isLeapYear($year)) ? 1 : 0;
 885                              }
 886                          }
 887                          if ($years == 2) {
 888                              if (($leapDays == 0) && (self::isLeapYear($startYear)) && ($days > 365)) {
 889                                  $leapDays = 1;
 890                              } elseif ($days < 366) {
 891                                  $years = 1;
 892                              }
 893                          }
 894                          $leapDays /= $years;
 895                      }
 896                      return $days / (365 + $leapDays);
 897                  case 2:
 898                      return self::DATEDIF($startDate, $endDate) / 360;
 899                  case 3:
 900                      return self::DATEDIF($startDate, $endDate) / 365;
 901                  case 4:
 902                      return self::DAYS360($startDate, $endDate, true) / 360;
 903              }
 904          }
 905          return PHPExcel_Calculation_Functions::VALUE();
 906      }
 907  
 908  
 909      /**
 910       * NETWORKDAYS
 911       *
 912       * Returns the number of whole working days between start_date and end_date. Working days
 913       * exclude weekends and any dates identified in holidays.
 914       * Use NETWORKDAYS to calculate employee benefits that accrue based on the number of days
 915       * worked during a specific term.
 916       *
 917       * Excel Function:
 918       *        NETWORKDAYS(startDate,endDate[,holidays[,holiday[,...]]])
 919       *
 920       * @access    public
 921       * @category Date/Time Functions
 922       * @param    mixed            $startDate        Excel date serial value (float), PHP date timestamp (integer),
 923       *                                            PHP DateTime object, or a standard date string
 924       * @param    mixed            $endDate        Excel date serial value (float), PHP date timestamp (integer),
 925       *                                            PHP DateTime object, or a standard date string
 926       * @param    mixed            $holidays,...    Optional series of Excel date serial value (float), PHP date
 927       *                                            timestamp (integer), PHP DateTime object, or a standard date
 928       *                                            strings that will be excluded from the working calendar, such
 929       *                                            as state and federal holidays and floating holidays.
 930       * @return    integer            Interval between the dates
 931       */
 932      public static function NETWORKDAYS($startDate, $endDate)
 933      {
 934          //    Retrieve the mandatory start and end date that are referenced in the function definition
 935          $startDate    = PHPExcel_Calculation_Functions::flattenSingleValue($startDate);
 936          $endDate    = PHPExcel_Calculation_Functions::flattenSingleValue($endDate);
 937          //    Flush the mandatory start and end date that are referenced in the function definition, and get the optional days
 938          $dateArgs = PHPExcel_Calculation_Functions::flattenArray(func_get_args());
 939          array_shift($dateArgs);
 940          array_shift($dateArgs);
 941  
 942          //    Validate the start and end dates
 943          if (is_string($startDate = $sDate = self::getDateValue($startDate))) {
 944              return PHPExcel_Calculation_Functions::VALUE();
 945          }
 946          $startDate = (float) floor($startDate);
 947          if (is_string($endDate = $eDate = self::getDateValue($endDate))) {
 948              return PHPExcel_Calculation_Functions::VALUE();
 949          }
 950          $endDate = (float) floor($endDate);
 951  
 952          if ($sDate > $eDate) {
 953              $startDate = $eDate;
 954              $endDate = $sDate;
 955          }
 956  
 957          // Execute function
 958          $startDoW = 6 - self::DAYOFWEEK($startDate, 2);
 959          if ($startDoW < 0) {
 960              $startDoW = 0;
 961          }
 962          $endDoW = self::DAYOFWEEK($endDate, 2);
 963          if ($endDoW >= 6) {
 964              $endDoW = 0;
 965          }
 966  
 967          $wholeWeekDays = floor(($endDate - $startDate) / 7) * 5;
 968          $partWeekDays = $endDoW + $startDoW;
 969          if ($partWeekDays > 5) {
 970              $partWeekDays -= 5;
 971          }
 972  
 973          //    Test any extra holiday parameters
 974          $holidayCountedArray = array();
 975          foreach ($dateArgs as $holidayDate) {
 976              if (is_string($holidayDate = self::getDateValue($holidayDate))) {
 977                  return PHPExcel_Calculation_Functions::VALUE();
 978              }
 979              if (($holidayDate >= $startDate) && ($holidayDate <= $endDate)) {
 980                  if ((self::DAYOFWEEK($holidayDate, 2) < 6) && (!in_array($holidayDate, $holidayCountedArray))) {
 981                      --$partWeekDays;
 982                      $holidayCountedArray[] = $holidayDate;
 983                  }
 984              }
 985          }
 986  
 987          if ($sDate > $eDate) {
 988              return 0 - ($wholeWeekDays + $partWeekDays);
 989          }
 990          return $wholeWeekDays + $partWeekDays;
 991      }
 992  
 993  
 994      /**
 995       * WORKDAY
 996       *
 997       * Returns the date that is the indicated number of working days before or after a date (the
 998       * starting date). Working days exclude weekends and any dates identified as holidays.
 999       * Use WORKDAY to exclude weekends or holidays when you calculate invoice due dates, expected
1000       * delivery times, or the number of days of work performed.
1001       *
1002       * Excel Function:
1003       *        WORKDAY(startDate,endDays[,holidays[,holiday[,...]]])
1004       *
1005       * @access    public
1006       * @category Date/Time Functions
1007       * @param    mixed        $startDate        Excel date serial value (float), PHP date timestamp (integer),
1008       *                                        PHP DateTime object, or a standard date string
1009       * @param    integer        $endDays        The number of nonweekend and nonholiday days before or after
1010       *                                        startDate. A positive value for days yields a future date; a
1011       *                                        negative value yields a past date.
1012       * @param    mixed        $holidays,...    Optional series of Excel date serial value (float), PHP date
1013       *                                        timestamp (integer), PHP DateTime object, or a standard date
1014       *                                        strings that will be excluded from the working calendar, such
1015       *                                        as state and federal holidays and floating holidays.
1016       * @return    mixed    Excel date/time serial value, PHP date/time serial value or PHP date/time object,
1017       *                        depending on the value of the ReturnDateType flag
1018       */
1019      public static function WORKDAY($startDate, $endDays)
1020      {
1021          //    Retrieve the mandatory start date and days that are referenced in the function definition
1022          $startDate    = PHPExcel_Calculation_Functions::flattenSingleValue($startDate);
1023          $endDays    = PHPExcel_Calculation_Functions::flattenSingleValue($endDays);
1024          //    Flush the mandatory start date and days that are referenced in the function definition, and get the optional days
1025          $dateArgs = PHPExcel_Calculation_Functions::flattenArray(func_get_args());
1026          array_shift($dateArgs);
1027          array_shift($dateArgs);
1028  
1029          if ((is_string($startDate = self::getDateValue($startDate))) || (!is_numeric($endDays))) {
1030              return PHPExcel_Calculation_Functions::VALUE();
1031          }
1032          $startDate = (float) floor($startDate);
1033          $endDays = (int) floor($endDays);
1034          //    If endDays is 0, we always return startDate
1035          if ($endDays == 0) {
1036              return $startDate;
1037          }
1038  
1039          $decrementing = ($endDays < 0) ? true : false;
1040  
1041          //    Adjust the start date if it falls over a weekend
1042  
1043          $startDoW = self::DAYOFWEEK($startDate, 3);
1044          if (self::DAYOFWEEK($startDate, 3) >= 5) {
1045              $startDate += ($decrementing) ? -$startDoW + 4: 7 - $startDoW;
1046              ($decrementing) ? $endDays++ : $endDays--;
1047          }
1048  
1049          //    Add endDays
1050          $endDate = (float) $startDate + (intval($endDays / 5) * 7) + ($endDays % 5);
1051  
1052          //    Adjust the calculated end date if it falls over a weekend
1053          $endDoW = self::DAYOFWEEK($endDate, 3);
1054          if ($endDoW >= 5) {
1055              $endDate += ($decrementing) ? -$endDoW + 4: 7 - $endDoW;
1056          }
1057  
1058          //    Test any extra holiday parameters
1059          if (!empty($dateArgs)) {
1060              $holidayCountedArray = $holidayDates = array();
1061              foreach ($dateArgs as $holidayDate) {
1062                  if (($holidayDate !== null) && (trim($holidayDate) > '')) {
1063                      if (is_string($holidayDate = self::getDateValue($holidayDate))) {
1064                          return PHPExcel_Calculation_Functions::VALUE();
1065                      }
1066                      if (self::DAYOFWEEK($holidayDate, 3) < 5) {
1067                          $holidayDates[] = $holidayDate;
1068                      }
1069                  }
1070              }
1071              if ($decrementing) {
1072                  rsort($holidayDates, SORT_NUMERIC);
1073              } else {
1074                  sort($holidayDates, SORT_NUMERIC);
1075              }
1076              foreach ($holidayDates as $holidayDate) {
1077                  if ($decrementing) {
1078                      if (($holidayDate <= $startDate) && ($holidayDate >= $endDate)) {
1079                          if (!in_array($holidayDate, $holidayCountedArray)) {
1080                              --$endDate;
1081                              $holidayCountedArray[] = $holidayDate;
1082                          }
1083                      }
1084                  } else {
1085                      if (($holidayDate >= $startDate) && ($holidayDate <= $endDate)) {
1086                          if (!in_array($holidayDate, $holidayCountedArray)) {
1087                              ++$endDate;
1088                              $holidayCountedArray[] = $holidayDate;
1089                          }
1090                      }
1091                  }
1092                  //    Adjust the calculated end date if it falls over a weekend
1093                  $endDoW = self::DAYOFWEEK($endDate, 3);
1094                  if ($endDoW >= 5) {
1095                      $endDate += ($decrementing) ? -$endDoW + 4 : 7 - $endDoW;
1096                  }
1097              }
1098          }
1099  
1100          switch (PHPExcel_Calculation_Functions::getReturnDateType()) {
1101              case PHPExcel_Calculation_Functions::RETURNDATE_EXCEL:
1102                  return (float) $endDate;
1103              case PHPExcel_Calculation_Functions::RETURNDATE_PHP_NUMERIC:
1104                  return (integer) PHPExcel_Shared_Date::ExcelToPHP($endDate);
1105              case PHPExcel_Calculation_Functions::RETURNDATE_PHP_OBJECT:
1106                  return PHPExcel_Shared_Date::ExcelToPHPObject($endDate);
1107          }
1108      }
1109  
1110  
1111      /**
1112       * DAYOFMONTH
1113       *
1114       * Returns the day of the month, for a specified date. The day is given as an integer
1115       * ranging from 1 to 31.
1116       *
1117       * Excel Function:
1118       *        DAY(dateValue)
1119       *
1120       * @param    mixed    $dateValue        Excel date serial value (float), PHP date timestamp (integer),
1121       *                                    PHP DateTime object, or a standard date string
1122       * @return    int        Day of the month
1123       */
1124      public static function DAYOFMONTH($dateValue = 1)
1125      {
1126          $dateValue    = PHPExcel_Calculation_Functions::flattenSingleValue($dateValue);
1127  
1128          if ($dateValue === null) {
1129              $dateValue = 1;
1130          } elseif (is_string($dateValue = self::getDateValue($dateValue))) {
1131              return PHPExcel_Calculation_Functions::VALUE();
1132          } elseif ($dateValue == 0.0) {
1133              return 0;
1134          } elseif ($dateValue < 0.0) {
1135              return PHPExcel_Calculation_Functions::NaN();
1136          }
1137  
1138          // Execute function
1139          $PHPDateObject = PHPExcel_Shared_Date::ExcelToPHPObject($dateValue);
1140  
1141          return (int) $PHPDateObject->format('j');
1142      }
1143  
1144  
1145      /**
1146       * DAYOFWEEK
1147       *
1148       * Returns the day of the week for a specified date. The day is given as an integer
1149       * ranging from 0 to 7 (dependent on the requested style).
1150       *
1151       * Excel Function:
1152       *        WEEKDAY(dateValue[,style])
1153       *
1154       * @param    mixed    $dateValue        Excel date serial value (float), PHP date timestamp (integer),
1155       *                                    PHP DateTime object, or a standard date string
1156       * @param    int        $style            A number that determines the type of return value
1157       *                                        1 or omitted    Numbers 1 (Sunday) through 7 (Saturday).
1158       *                                        2                Numbers 1 (Monday) through 7 (Sunday).
1159       *                                        3                Numbers 0 (Monday) through 6 (Sunday).
1160       * @return    int        Day of the week value
1161       */
1162      public static function DAYOFWEEK($dateValue = 1, $style = 1)
1163      {
1164          $dateValue    = PHPExcel_Calculation_Functions::flattenSingleValue($dateValue);
1165          $style        = PHPExcel_Calculation_Functions::flattenSingleValue($style);
1166  
1167          if (!is_numeric($style)) {
1168              return PHPExcel_Calculation_Functions::VALUE();
1169          } elseif (($style < 1) || ($style > 3)) {
1170              return PHPExcel_Calculation_Functions::NaN();
1171          }
1172          $style = floor($style);
1173  
1174          if ($dateValue === null) {
1175              $dateValue = 1;
1176          } elseif (is_string($dateValue = self::getDateValue($dateValue))) {
1177              return PHPExcel_Calculation_Functions::VALUE();
1178          } elseif ($dateValue < 0.0) {
1179              return PHPExcel_Calculation_Functions::NaN();
1180          }
1181  
1182          // Execute function
1183          $PHPDateObject = PHPExcel_Shared_Date::ExcelToPHPObject($dateValue);
1184          $DoW = $PHPDateObject->format('w');
1185  
1186          $firstDay = 1;
1187          switch ($style) {
1188              case 1:
1189                  ++$DoW;
1190                  break;
1191              case 2:
1192                  if ($DoW == 0) {
1193                      $DoW = 7;
1194                  }
1195                  break;
1196              case 3:
1197                  if ($DoW == 0) {
1198                      $DoW = 7;
1199                  }
1200                  $firstDay = 0;
1201                  --$DoW;
1202                  break;
1203          }
1204          if (PHPExcel_Calculation_Functions::getCompatibilityMode() == PHPExcel_Calculation_Functions::COMPATIBILITY_EXCEL) {
1205              //    Test for Excel's 1900 leap year, and introduce the error as required
1206              if (($PHPDateObject->format('Y') == 1900) && ($PHPDateObject->format('n') <= 2)) {
1207                  --$DoW;
1208                  if ($DoW < $firstDay) {
1209                      $DoW += 7;
1210                  }
1211              }
1212          }
1213  
1214          return (int) $DoW;
1215      }
1216  
1217  
1218      /**
1219       * WEEKOFYEAR
1220       *
1221       * Returns the week of the year for a specified date.
1222       * The WEEKNUM function considers the week containing January 1 to be the first week of the year.
1223       * However, there is a European standard that defines the first week as the one with the majority
1224       * of days (four or more) falling in the new year. This means that for years in which there are
1225       * three days or less in the first week of January, the WEEKNUM function returns week numbers
1226       * that are incorrect according to the European standard.
1227       *
1228       * Excel Function:
1229       *        WEEKNUM(dateValue[,style])
1230       *
1231       * @param    mixed    $dateValue        Excel date serial value (float), PHP date timestamp (integer),
1232       *                                    PHP DateTime object, or a standard date string
1233       * @param    boolean    $method            Week begins on Sunday or Monday
1234       *                                        1 or omitted    Week begins on Sunday.
1235       *                                        2                Week begins on Monday.
1236       * @return    int        Week Number
1237       */
1238      public static function WEEKOFYEAR($dateValue = 1, $method = 1)
1239      {
1240          $dateValue    = PHPExcel_Calculation_Functions::flattenSingleValue($dateValue);
1241          $method        = PHPExcel_Calculation_Functions::flattenSingleValue($method);
1242  
1243          if (!is_numeric($method)) {
1244              return PHPExcel_Calculation_Functions::VALUE();
1245          } elseif (($method < 1) || ($method > 2)) {
1246              return PHPExcel_Calculation_Functions::NaN();
1247          }
1248          $method = floor($method);
1249  
1250          if ($dateValue === null) {
1251              $dateValue = 1;
1252          } elseif (is_string($dateValue = self::getDateValue($dateValue))) {
1253              return PHPExcel_Calculation_Functions::VALUE();
1254          } elseif ($dateValue < 0.0) {
1255              return PHPExcel_Calculation_Functions::NaN();
1256          }
1257  
1258          // Execute function
1259          $PHPDateObject = PHPExcel_Shared_Date::ExcelToPHPObject($dateValue);
1260          $dayOfYear = $PHPDateObject->format('z');
1261          $dow = $PHPDateObject->format('w');
1262          $PHPDateObject->modify('-' . $dayOfYear . ' days');
1263          $dow = $PHPDateObject->format('w');
1264          $daysInFirstWeek = 7 - (($dow + (2 - $method)) % 7);
1265          $dayOfYear -= $daysInFirstWeek;
1266          $weekOfYear = ceil($dayOfYear / 7) + 1;
1267  
1268          return (int) $weekOfYear;
1269      }
1270  
1271  
1272      /**
1273       * MONTHOFYEAR
1274       *
1275       * Returns the month of a date represented by a serial number.
1276       * The month is given as an integer, ranging from 1 (January) to 12 (December).
1277       *
1278       * Excel Function:
1279       *        MONTH(dateValue)
1280       *
1281       * @param    mixed    $dateValue        Excel date serial value (float), PHP date timestamp (integer),
1282       *                                    PHP DateTime object, or a standard date string
1283       * @return    int        Month of the year
1284       */
1285      public static function MONTHOFYEAR($dateValue = 1)
1286      {
1287          $dateValue    = PHPExcel_Calculation_Functions::flattenSingleValue($dateValue);
1288  
1289          if ($dateValue === null) {
1290              $dateValue = 1;
1291          } elseif (is_string($dateValue = self::getDateValue($dateValue))) {
1292              return PHPExcel_Calculation_Functions::VALUE();
1293          } elseif ($dateValue < 0.0) {
1294              return PHPExcel_Calculation_Functions::NaN();
1295          }
1296  
1297          // Execute function
1298          $PHPDateObject = PHPExcel_Shared_Date::ExcelToPHPObject($dateValue);
1299  
1300          return (int) $PHPDateObject->format('n');
1301      }
1302  
1303  
1304      /**
1305       * YEAR
1306       *
1307       * Returns the year corresponding to a date.
1308       * The year is returned as an integer in the range 1900-9999.
1309       *
1310       * Excel Function:
1311       *        YEAR(dateValue)
1312       *
1313       * @param    mixed    $dateValue        Excel date serial value (float), PHP date timestamp (integer),
1314       *                                    PHP DateTime object, or a standard date string
1315       * @return    int        Year
1316       */
1317      public static function YEAR($dateValue = 1)
1318      {
1319          $dateValue    = PHPExcel_Calculation_Functions::flattenSingleValue($dateValue);
1320  
1321          if ($dateValue === null) {
1322              $dateValue = 1;
1323          } elseif (is_string($dateValue = self::getDateValue($dateValue))) {
1324              return PHPExcel_Calculation_Functions::VALUE();
1325          } elseif ($dateValue < 0.0) {
1326              return PHPExcel_Calculation_Functions::NaN();
1327          }
1328  
1329          // Execute function
1330          $PHPDateObject = PHPExcel_Shared_Date::ExcelToPHPObject($dateValue);
1331  
1332          return (int) $PHPDateObject->format('Y');
1333      }
1334  
1335  
1336      /**
1337       * HOUROFDAY
1338       *
1339       * Returns the hour of a time value.
1340       * The hour is given as an integer, ranging from 0 (12:00 A.M.) to 23 (11:00 P.M.).
1341       *
1342       * Excel Function:
1343       *        HOUR(timeValue)
1344       *
1345       * @param    mixed    $timeValue        Excel date serial value (float), PHP date timestamp (integer),
1346       *                                    PHP DateTime object, or a standard time string
1347       * @return    int        Hour
1348       */
1349      public static function HOUROFDAY($timeValue = 0)
1350      {
1351          $timeValue    = PHPExcel_Calculation_Functions::flattenSingleValue($timeValue);
1352  
1353          if (!is_numeric($timeValue)) {
1354              if (PHPExcel_Calculation_Functions::getCompatibilityMode() == PHPExcel_Calculation_Functions::COMPATIBILITY_GNUMERIC) {
1355                  $testVal = strtok($timeValue, '/-: ');
1356                  if (strlen($testVal) < strlen($timeValue)) {
1357                      return PHPExcel_Calculation_Functions::VALUE();
1358                  }
1359              }
1360              $timeValue = self::getTimeValue($timeValue);
1361              if (is_string($timeValue)) {
1362                  return PHPExcel_Calculation_Functions::VALUE();
1363              }
1364          }
1365          // Execute function
1366          if ($timeValue >= 1) {
1367              $timeValue = fmod($timeValue, 1);
1368          } elseif ($timeValue < 0.0) {
1369              return PHPExcel_Calculation_Functions::NaN();
1370          }
1371          $timeValue = PHPExcel_Shared_Date::ExcelToPHP($timeValue);
1372  
1373          return (int) gmdate('G', $timeValue);
1374      }
1375  
1376  
1377      /**
1378       * MINUTEOFHOUR
1379       *
1380       * Returns the minutes of a time value.
1381       * The minute is given as an integer, ranging from 0 to 59.
1382       *
1383       * Excel Function:
1384       *        MINUTE(timeValue)
1385       *
1386       * @param    mixed    $timeValue        Excel date serial value (float), PHP date timestamp (integer),
1387       *                                    PHP DateTime object, or a standard time string
1388       * @return    int        Minute
1389       */
1390      public static function MINUTEOFHOUR($timeValue = 0)
1391      {
1392          $timeValue = $timeTester    = PHPExcel_Calculation_Functions::flattenSingleValue($timeValue);
1393  
1394          if (!is_numeric($timeValue)) {
1395              if (PHPExcel_Calculation_Functions::getCompatibilityMode() == PHPExcel_Calculation_Functions::COMPATIBILITY_GNUMERIC) {
1396                  $testVal = strtok($timeValue, '/-: ');
1397                  if (strlen($testVal) < strlen($timeValue)) {
1398                      return PHPExcel_Calculation_Functions::VALUE();
1399                  }
1400              }
1401              $timeValue = self::getTimeValue($timeValue);
1402              if (is_string($timeValue)) {
1403                  return PHPExcel_Calculation_Functions::VALUE();
1404              }
1405          }
1406          // Execute function
1407          if ($timeValue >= 1) {
1408              $timeValue = fmod($timeValue, 1);
1409          } elseif ($timeValue < 0.0) {
1410              return PHPExcel_Calculation_Functions::NaN();
1411          }
1412          $timeValue = PHPExcel_Shared_Date::ExcelToPHP($timeValue);
1413  
1414          return (int) gmdate('i', $timeValue);
1415      }
1416  
1417  
1418      /**
1419       * SECONDOFMINUTE
1420       *
1421       * Returns the seconds of a time value.
1422       * The second is given as an integer in the range 0 (zero) to 59.
1423       *
1424       * Excel Function:
1425       *        SECOND(timeValue)
1426       *
1427       * @param    mixed    $timeValue        Excel date serial value (float), PHP date timestamp (integer),
1428       *                                    PHP DateTime object, or a standard time string
1429       * @return    int        Second
1430       */
1431      public static function SECONDOFMINUTE($timeValue = 0)
1432      {
1433          $timeValue    = PHPExcel_Calculation_Functions::flattenSingleValue($timeValue);
1434  
1435          if (!is_numeric($timeValue)) {
1436              if (PHPExcel_Calculation_Functions::getCompatibilityMode() == PHPExcel_Calculation_Functions::COMPATIBILITY_GNUMERIC) {
1437                  $testVal = strtok($timeValue, '/-: ');
1438                  if (strlen($testVal) < strlen($timeValue)) {
1439                      return PHPExcel_Calculation_Functions::VALUE();
1440                  }
1441              }
1442              $timeValue = self::getTimeValue($timeValue);
1443              if (is_string($timeValue)) {
1444                  return PHPExcel_Calculation_Functions::VALUE();
1445              }
1446          }
1447          // Execute function
1448          if ($timeValue >= 1) {
1449              $timeValue = fmod($timeValue, 1);
1450          } elseif ($timeValue < 0.0) {
1451              return PHPExcel_Calculation_Functions::NaN();
1452          }
1453          $timeValue = PHPExcel_Shared_Date::ExcelToPHP($timeValue);
1454  
1455          return (int) gmdate('s', $timeValue);
1456      }
1457  
1458  
1459      /**
1460       * EDATE
1461       *
1462       * Returns the serial number that represents the date that is the indicated number of months
1463       * before or after a specified date (the start_date).
1464       * Use EDATE to calculate maturity dates or due dates that fall on the same day of the month
1465       * as the date of issue.
1466       *
1467       * Excel Function:
1468       *        EDATE(dateValue,adjustmentMonths)
1469       *
1470       * @param    mixed    $dateValue            Excel date serial value (float), PHP date timestamp (integer),
1471       *                                        PHP DateTime object, or a standard date string
1472       * @param    int        $adjustmentMonths    The number of months before or after start_date.
1473       *                                        A positive value for months yields a future date;
1474       *                                        a negative value yields a past date.
1475       * @return    mixed    Excel date/time serial value, PHP date/time serial value or PHP date/time object,
1476       *                        depending on the value of the ReturnDateType flag
1477       */
1478      public static function EDATE($dateValue = 1, $adjustmentMonths = 0)
1479      {
1480          $dateValue            = PHPExcel_Calculation_Functions::flattenSingleValue($dateValue);
1481          $adjustmentMonths    = PHPExcel_Calculation_Functions::flattenSingleValue($adjustmentMonths);
1482  
1483          if (!is_numeric($adjustmentMonths)) {
1484              return PHPExcel_Calculation_Functions::VALUE();
1485          }
1486          $adjustmentMonths = floor($adjustmentMonths);
1487  
1488          if (is_string($dateValue = self::getDateValue($dateValue))) {
1489              return PHPExcel_Calculation_Functions::VALUE();
1490          }
1491  
1492          // Execute function
1493          $PHPDateObject = self::adjustDateByMonths($dateValue, $adjustmentMonths);
1494  
1495          switch (PHPExcel_Calculation_Functions::getReturnDateType()) {
1496              case PHPExcel_Calculation_Functions::RETURNDATE_EXCEL:
1497                  return (float) PHPExcel_Shared_Date::PHPToExcel($PHPDateObject);
1498              case PHPExcel_Calculation_Functions::RETURNDATE_PHP_NUMERIC:
1499                  return (integer) PHPExcel_Shared_Date::ExcelToPHP(PHPExcel_Shared_Date::PHPToExcel($PHPDateObject));
1500              case PHPExcel_Calculation_Functions::RETURNDATE_PHP_OBJECT:
1501                  return $PHPDateObject;
1502          }
1503      }
1504  
1505  
1506      /**
1507       * EOMONTH
1508       *
1509       * Returns the date value for the last day of the month that is the indicated number of months
1510       * before or after start_date.
1511       * Use EOMONTH to calculate maturity dates or due dates that fall on the last day of the month.
1512       *
1513       * Excel Function:
1514       *        EOMONTH(dateValue,adjustmentMonths)
1515       *
1516       * @param    mixed    $dateValue            Excel date serial value (float), PHP date timestamp (integer),
1517       *                                        PHP DateTime object, or a standard date string
1518       * @param    int        $adjustmentMonths    The number of months before or after start_date.
1519       *                                        A positive value for months yields a future date;
1520       *                                        a negative value yields a past date.
1521       * @return    mixed    Excel date/time serial value, PHP date/time serial value or PHP date/time object,
1522       *                        depending on the value of the ReturnDateType flag
1523       */
1524      public static function EOMONTH($dateValue = 1, $adjustmentMonths = 0)
1525      {
1526          $dateValue            = PHPExcel_Calculation_Functions::flattenSingleValue($dateValue);
1527          $adjustmentMonths    = PHPExcel_Calculation_Functions::flattenSingleValue($adjustmentMonths);
1528  
1529          if (!is_numeric($adjustmentMonths)) {
1530              return PHPExcel_Calculation_Functions::VALUE();
1531          }
1532          $adjustmentMonths = floor($adjustmentMonths);
1533  
1534          if (is_string($dateValue = self::getDateValue($dateValue))) {
1535              return PHPExcel_Calculation_Functions::VALUE();
1536          }
1537  
1538          // Execute function
1539          $PHPDateObject = self::adjustDateByMonths($dateValue, $adjustmentMonths+1);
1540          $adjustDays = (int) $PHPDateObject->format('d');
1541          $adjustDaysString = '-' . $adjustDays . ' days';
1542          $PHPDateObject->modify($adjustDaysString);
1543  
1544          switch (PHPExcel_Calculation_Functions::getReturnDateType()) {
1545              case PHPExcel_Calculation_Functions::RETURNDATE_EXCEL:
1546                  return (float) PHPExcel_Shared_Date::PHPToExcel($PHPDateObject);
1547              case PHPExcel_Calculation_Functions::RETURNDATE_PHP_NUMERIC:
1548                  return (integer) PHPExcel_Shared_Date::ExcelToPHP(PHPExcel_Shared_Date::PHPToExcel($PHPDateObject));
1549              case PHPExcel_Calculation_Functions::RETURNDATE_PHP_OBJECT:
1550                  return $PHPDateObject;
1551          }
1552      }
1553  }


Generated: Thu Aug 11 10:00:09 2016 Cross-referenced by PHPXref 0.7.1