PluginProbe
Visualizer – Tables & Charts Manager with Built-in AI Generator / 3.0.3
Visualizer – Tables & Charts Manager with Built-in AI Generator v3.0.3
4.0.8 4.0.7 4.0.6 4.0.5 4.0.4 4.0.3 3.0.5 3.0.6 3.0.7 3.0.8 3.0.9 3.1.0 3.1.1 3.1.2 3.1.3 3.10.0 3.10.1 3.10.10 3.10.11 3.10.12 3.10.13 3.10.14 3.10.15 3.10.2 3.10.3 All 149 releases
visualizer / vendor / phpoffice / phpexcel / Classes / PHPExcel / Calculation / DateTime.php

DateTime.php in Visualizer – Tables & Charts Manager with Built-in AI Generator 3.0.3, at vendor/phpoffice/phpexcel/Classes/PHPExcel/Calculation/DateTime.php

1,486 lines 54.7 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
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 ##VERSION##, ##DATE##
26 */
27
28
29 /** PHPExcel root directory */
30 if (!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 */
46 class 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 ($dateValue === null) {
1075 $dateValue = 1;
1076 } elseif (is_string($dateValue = self::_getDateValue($dateValue))) {
1077 return PHPExcel_Calculation_Functions::VALUE();
1078 } elseif ($dateValue == 0.0) {
1079 return 0;
1080 } elseif ($dateValue < 0.0) {
1081 return PHPExcel_Calculation_Functions::NaN();
1082 }
1083
1084 // Execute function
1085 $PHPDateObject = PHPExcel_Shared_Date::ExcelToPHPObject($dateValue);
1086
1087 return (int) $PHPDateObject->format('j');
1088 } // function DAYOFMONTH()
1089
1090
1091 /**
1092 * DAYOFWEEK
1093 *
1094 * Returns the day of the week for a specified date. The day is given as an integer
1095 * ranging from 0 to 7 (dependent on the requested style).
1096 *
1097 * Excel Function:
1098 * WEEKDAY(dateValue[,style])
1099 *
1100 * @param mixed $dateValue Excel date serial value (float), PHP date timestamp (integer),
1101 * PHP DateTime object, or a standard date string
1102 * @param int $style A number that determines the type of return value
1103 * 1 or omitted Numbers 1 (Sunday) through 7 (Saturday).
1104 * 2 Numbers 1 (Monday) through 7 (Sunday).
1105 * 3 Numbers 0 (Monday) through 6 (Sunday).
1106 * @return int Day of the week value
1107 */
1108 public static function DAYOFWEEK($dateValue = 1, $style = 1) {
1109 $dateValue = PHPExcel_Calculation_Functions::flattenSingleValue($dateValue);
1110 $style = PHPExcel_Calculation_Functions::flattenSingleValue($style);
1111
1112 if (!is_numeric($style)) {
1113 return PHPExcel_Calculation_Functions::VALUE();
1114 } elseif (($style < 1) || ($style > 3)) {
1115 return PHPExcel_Calculation_Functions::NaN();
1116 }
1117 $style = floor($style);
1118
1119 if ($dateValue === null) {
1120 $dateValue = 1;
1121 } elseif (is_string($dateValue = self::_getDateValue($dateValue))) {
1122 return PHPExcel_Calculation_Functions::VALUE();
1123 } elseif ($dateValue < 0.0) {
1124 return PHPExcel_Calculation_Functions::NaN();
1125 }
1126
1127 // Execute function
1128 $PHPDateObject = PHPExcel_Shared_Date::ExcelToPHPObject($dateValue);
1129 $DoW = $PHPDateObject->format('w');
1130
1131 $firstDay = 1;
1132 switch ($style) {
1133 case 1: ++$DoW;
1134 break;
1135 case 2: if ($DoW == 0) { $DoW = 7; }
1136 break;
1137 case 3: if ($DoW == 0) { $DoW = 7; }
1138 $firstDay = 0;
1139 --$DoW;
1140 break;
1141 }
1142 if (PHPExcel_Calculation_Functions::getCompatibilityMode() == PHPExcel_Calculation_Functions::COMPATIBILITY_EXCEL) {
1143 // Test for Excel's 1900 leap year, and introduce the error as required
1144 if (($PHPDateObject->format('Y') == 1900) && ($PHPDateObject->format('n') <= 2)) {
1145 --$DoW;
1146 if ($DoW < $firstDay) {
1147 $DoW += 7;
1148 }
1149 }
1150 }
1151
1152 return (int) $DoW;
1153 } // function DAYOFWEEK()
1154
1155
1156 /**
1157 * WEEKOFYEAR
1158 *
1159 * Returns the week of the year for a specified date.
1160 * The WEEKNUM function considers the week containing January 1 to be the first week of the year.
1161 * However, there is a European standard that defines the first week as the one with the majority
1162 * of days (four or more) falling in the new year. This means that for years in which there are
1163 * three days or less in the first week of January, the WEEKNUM function returns week numbers
1164 * that are incorrect according to the European standard.
1165 *
1166 * Excel Function:
1167 * WEEKNUM(dateValue[,style])
1168 *
1169 * @param mixed $dateValue Excel date serial value (float), PHP date timestamp (integer),
1170 * PHP DateTime object, or a standard date string
1171 * @param boolean $method Week begins on Sunday or Monday
1172 * 1 or omitted Week begins on Sunday.
1173 * 2 Week begins on Monday.
1174 * @return int Week Number
1175 */
1176 public static function WEEKOFYEAR($dateValue = 1, $method = 1) {
1177 $dateValue = PHPExcel_Calculation_Functions::flattenSingleValue($dateValue);
1178 $method = PHPExcel_Calculation_Functions::flattenSingleValue($method);
1179
1180 if (!is_numeric($method)) {
1181 return PHPExcel_Calculation_Functions::VALUE();
1182 } elseif (($method < 1) || ($method > 2)) {
1183 return PHPExcel_Calculation_Functions::NaN();
1184 }
1185 $method = floor($method);
1186
1187 if ($dateValue === null) {
1188 $dateValue = 1;
1189 } elseif (is_string($dateValue = self::_getDateValue($dateValue))) {
1190 return PHPExcel_Calculation_Functions::VALUE();
1191 } elseif ($dateValue < 0.0) {
1192 return PHPExcel_Calculation_Functions::NaN();
1193 }
1194
1195 // Execute function
1196 $PHPDateObject = PHPExcel_Shared_Date::ExcelToPHPObject($dateValue);
1197 $dayOfYear = $PHPDateObject->format('z');
1198 $dow = $PHPDateObject->format('w');
1199 $PHPDateObject->modify('-'.$dayOfYear.' days');
1200 $dow = $PHPDateObject->format('w');
1201 $daysInFirstWeek = 7 - (($dow + (2 - $method)) % 7);
1202 $dayOfYear -= $daysInFirstWeek;
1203 $weekOfYear = ceil($dayOfYear / 7) + 1;
1204
1205 return (int) $weekOfYear;
1206 } // function WEEKOFYEAR()
1207
1208
1209 /**
1210 * MONTHOFYEAR
1211 *
1212 * Returns the month of a date represented by a serial number.
1213 * The month is given as an integer, ranging from 1 (January) to 12 (December).
1214 *
1215 * Excel Function:
1216 * MONTH(dateValue)
1217 *
1218 * @param mixed $dateValue Excel date serial value (float), PHP date timestamp (integer),
1219 * PHP DateTime object, or a standard date string
1220 * @return int Month of the year
1221 */
1222 public static function MONTHOFYEAR($dateValue = 1) {
1223 $dateValue = PHPExcel_Calculation_Functions::flattenSingleValue($dateValue);
1224
1225 if ($dateValue === null) {
1226 $dateValue = 1;
1227 } elseif (is_string($dateValue = self::_getDateValue($dateValue))) {
1228 return PHPExcel_Calculation_Functions::VALUE();
1229 } elseif ($dateValue < 0.0) {
1230 return PHPExcel_Calculation_Functions::NaN();
1231 }
1232
1233 // Execute function
1234 $PHPDateObject = PHPExcel_Shared_Date::ExcelToPHPObject($dateValue);
1235
1236 return (int) $PHPDateObject->format('n');
1237 } // function MONTHOFYEAR()
1238
1239
1240 /**
1241 * YEAR
1242 *
1243 * Returns the year corresponding to a date.
1244 * The year is returned as an integer in the range 1900-9999.
1245 *
1246 * Excel Function:
1247 * YEAR(dateValue)
1248 *
1249 * @param mixed $dateValue Excel date serial value (float), PHP date timestamp (integer),
1250 * PHP DateTime object, or a standard date string
1251 * @return int Year
1252 */
1253 public static function YEAR($dateValue = 1) {
1254 $dateValue = PHPExcel_Calculation_Functions::flattenSingleValue($dateValue);
1255
1256 if ($dateValue === null) {
1257 $dateValue = 1;
1258 } elseif (is_string($dateValue = self::_getDateValue($dateValue))) {
1259 return PHPExcel_Calculation_Functions::VALUE();
1260 } elseif ($dateValue < 0.0) {
1261 return PHPExcel_Calculation_Functions::NaN();
1262 }
1263
1264 // Execute function
1265 $PHPDateObject = PHPExcel_Shared_Date::ExcelToPHPObject($dateValue);
1266
1267 return (int) $PHPDateObject->format('Y');
1268 } // function YEAR()
1269
1270
1271 /**
1272 * HOUROFDAY
1273 *
1274 * Returns the hour of a time value.
1275 * The hour is given as an integer, ranging from 0 (12:00 A.M.) to 23 (11:00 P.M.).
1276 *
1277 * Excel Function:
1278 * HOUR(timeValue)
1279 *
1280 * @param mixed $timeValue Excel date serial value (float), PHP date timestamp (integer),
1281 * PHP DateTime object, or a standard time string
1282 * @return int Hour
1283 */
1284 public static function HOUROFDAY($timeValue = 0) {
1285 $timeValue = PHPExcel_Calculation_Functions::flattenSingleValue($timeValue);
1286
1287 if (!is_numeric($timeValue)) {
1288 if (PHPExcel_Calculation_Functions::getCompatibilityMode() == PHPExcel_Calculation_Functions::COMPATIBILITY_GNUMERIC) {
1289 $testVal = strtok($timeValue,'/-: ');
1290 if (strlen($testVal) < strlen($timeValue)) {
1291 return PHPExcel_Calculation_Functions::VALUE();
1292 }
1293 }
1294 $timeValue = self::_getTimeValue($timeValue);
1295 if (is_string($timeValue)) {
1296 return PHPExcel_Calculation_Functions::VALUE();
1297 }
1298 }
1299 // Execute function
1300 if ($timeValue >= 1) {
1301 $timeValue = fmod($timeValue,1);
1302 } elseif ($timeValue < 0.0) {
1303 return PHPExcel_Calculation_Functions::NaN();
1304 }
1305 $timeValue = PHPExcel_Shared_Date::ExcelToPHP($timeValue);
1306
1307 return (int) gmdate('G',$timeValue);
1308 } // function HOUROFDAY()
1309
1310
1311 /**
1312 * MINUTEOFHOUR
1313 *
1314 * Returns the minutes of a time value.
1315 * The minute is given as an integer, ranging from 0 to 59.
1316 *
1317 * Excel Function:
1318 * MINUTE(timeValue)
1319 *
1320 * @param mixed $timeValue Excel date serial value (float), PHP date timestamp (integer),
1321 * PHP DateTime object, or a standard time string
1322 * @return int Minute
1323 */
1324 public static function MINUTEOFHOUR($timeValue = 0) {
1325 $timeValue = $timeTester = PHPExcel_Calculation_Functions::flattenSingleValue($timeValue);
1326
1327 if (!is_numeric($timeValue)) {
1328 if (PHPExcel_Calculation_Functions::getCompatibilityMode() == PHPExcel_Calculation_Functions::COMPATIBILITY_GNUMERIC) {
1329 $testVal = strtok($timeValue,'/-: ');
1330 if (strlen($testVal) < strlen($timeValue)) {
1331 return PHPExcel_Calculation_Functions::VALUE();
1332 }
1333 }
1334 $timeValue = self::_getTimeValue($timeValue);
1335 if (is_string($timeValue)) {
1336 return PHPExcel_Calculation_Functions::VALUE();
1337 }
1338 }
1339 // Execute function
1340 if ($timeValue >= 1) {
1341 $timeValue = fmod($timeValue,1);
1342 } elseif ($timeValue < 0.0) {
1343 return PHPExcel_Calculation_Functions::NaN();
1344 }
1345 $timeValue = PHPExcel_Shared_Date::ExcelToPHP($timeValue);
1346
1347 return (int) gmdate('i',$timeValue);
1348 } // function MINUTEOFHOUR()
1349
1350
1351 /**
1352 * SECONDOFMINUTE
1353 *
1354 * Returns the seconds of a time value.
1355 * The second is given as an integer in the range 0 (zero) to 59.
1356 *
1357 * Excel Function:
1358 * SECOND(timeValue)
1359 *
1360 * @param mixed $timeValue Excel date serial value (float), PHP date timestamp (integer),
1361 * PHP DateTime object, or a standard time string
1362 * @return int Second
1363 */
1364 public static function SECONDOFMINUTE($timeValue = 0) {
1365 $timeValue = PHPExcel_Calculation_Functions::flattenSingleValue($timeValue);
1366
1367 if (!is_numeric($timeValue)) {
1368 if (PHPExcel_Calculation_Functions::getCompatibilityMode() == PHPExcel_Calculation_Functions::COMPATIBILITY_GNUMERIC) {
1369 $testVal = strtok($timeValue,'/-: ');
1370 if (strlen($testVal) < strlen($timeValue)) {
1371 return PHPExcel_Calculation_Functions::VALUE();
1372 }
1373 }
1374 $timeValue = self::_getTimeValue($timeValue);
1375 if (is_string($timeValue)) {
1376 return PHPExcel_Calculation_Functions::VALUE();
1377 }
1378 }
1379 // Execute function
1380 if ($timeValue >= 1) {
1381 $timeValue = fmod($timeValue,1);
1382 } elseif ($timeValue < 0.0) {
1383 return PHPExcel_Calculation_Functions::NaN();
1384 }
1385 $timeValue = PHPExcel_Shared_Date::ExcelToPHP($timeValue);
1386
1387 return (int) gmdate('s',$timeValue);
1388 } // function SECONDOFMINUTE()
1389
1390
1391 /**
1392 * EDATE
1393 *
1394 * Returns the serial number that represents the date that is the indicated number of months
1395 * before or after a specified date (the start_date).
1396 * Use EDATE to calculate maturity dates or due dates that fall on the same day of the month
1397 * as the date of issue.
1398 *
1399 * Excel Function:
1400 * EDATE(dateValue,adjustmentMonths)
1401 *
1402 * @param mixed $dateValue Excel date serial value (float), PHP date timestamp (integer),
1403 * PHP DateTime object, or a standard date string
1404 * @param int $adjustmentMonths The number of months before or after start_date.
1405 * A positive value for months yields a future date;
1406 * a negative value yields a past date.
1407 * @return mixed Excel date/time serial value, PHP date/time serial value or PHP date/time object,
1408 * depending on the value of the ReturnDateType flag
1409 */
1410 public static function EDATE($dateValue = 1, $adjustmentMonths = 0) {
1411 $dateValue = PHPExcel_Calculation_Functions::flattenSingleValue($dateValue);
1412 $adjustmentMonths = PHPExcel_Calculation_Functions::flattenSingleValue($adjustmentMonths);
1413
1414 if (!is_numeric($adjustmentMonths)) {
1415 return PHPExcel_Calculation_Functions::VALUE();
1416 }
1417 $adjustmentMonths = floor($adjustmentMonths);
1418
1419 if (is_string($dateValue = self::_getDateValue($dateValue))) {
1420 return PHPExcel_Calculation_Functions::VALUE();
1421 }
1422
1423 // Execute function
1424 $PHPDateObject = self::_adjustDateByMonths($dateValue,$adjustmentMonths);
1425
1426 switch (PHPExcel_Calculation_Functions::getReturnDateType()) {
1427 case PHPExcel_Calculation_Functions::RETURNDATE_EXCEL :
1428 return (float) PHPExcel_Shared_Date::PHPToExcel($PHPDateObject);
1429 case PHPExcel_Calculation_Functions::RETURNDATE_PHP_NUMERIC :
1430 return (integer) PHPExcel_Shared_Date::ExcelToPHP(PHPExcel_Shared_Date::PHPToExcel($PHPDateObject));
1431 case PHPExcel_Calculation_Functions::RETURNDATE_PHP_OBJECT :
1432 return $PHPDateObject;
1433 }
1434 } // function EDATE()
1435
1436
1437 /**
1438 * EOMONTH
1439 *
1440 * Returns the date value for the last day of the month that is the indicated number of months
1441 * before or after start_date.
1442 * Use EOMONTH to calculate maturity dates or due dates that fall on the last day of the month.
1443 *
1444 * Excel Function:
1445 * EOMONTH(dateValue,adjustmentMonths)
1446 *
1447 * @param mixed $dateValue Excel date serial value (float), PHP date timestamp (integer),
1448 * PHP DateTime object, or a standard date string
1449 * @param int $adjustmentMonths The number of months before or after start_date.
1450 * A positive value for months yields a future date;
1451 * a negative value yields a past date.
1452 * @return mixed Excel date/time serial value, PHP date/time serial value or PHP date/time object,
1453 * depending on the value of the ReturnDateType flag
1454 */
1455 public static function EOMONTH($dateValue = 1, $adjustmentMonths = 0) {
1456 $dateValue = PHPExcel_Calculation_Functions::flattenSingleValue($dateValue);
1457 $adjustmentMonths = PHPExcel_Calculation_Functions::flattenSingleValue($adjustmentMonths);
1458
1459 if (!is_numeric($adjustmentMonths)) {
1460 return PHPExcel_Calculation_Functions::VALUE();
1461 }
1462 $adjustmentMonths = floor($adjustmentMonths);
1463
1464 if (is_string($dateValue = self::_getDateValue($dateValue))) {
1465 return PHPExcel_Calculation_Functions::VALUE();
1466 }
1467
1468 // Execute function
1469 $PHPDateObject = self::_adjustDateByMonths($dateValue,$adjustmentMonths+1);
1470 $adjustDays = (int) $PHPDateObject->format('d');
1471 $adjustDaysString = '-'.$adjustDays.' days';
1472 $PHPDateObject->modify($adjustDaysString);
1473
1474 switch (PHPExcel_Calculation_Functions::getReturnDateType()) {
1475 case PHPExcel_Calculation_Functions::RETURNDATE_EXCEL :
1476 return (float) PHPExcel_Shared_Date::PHPToExcel($PHPDateObject);
1477 case PHPExcel_Calculation_Functions::RETURNDATE_PHP_NUMERIC :
1478 return (integer) PHPExcel_Shared_Date::ExcelToPHP(PHPExcel_Shared_Date::PHPToExcel($PHPDateObject));
1479 case PHPExcel_Calculation_Functions::RETURNDATE_PHP_OBJECT :
1480 return $PHPDateObject;
1481 }
1482 } // function EOMONTH()
1483
1484 } // class PHPExcel_Calculation_DateTime
1485
1486