source: sourcecode/application/libraries/PHPExcel/Calculation/DateTime.php @ 1

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