Failed Conditions
Push — develop ( 0ef1b5...a1e8c8 )
by Mark
34:44
created

DateTime::WORKDAY()   F

Complexity

Conditions 30
Paths 392

Size

Total Lines 86
Code Lines 51

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 43
CRAP Score 32.4696

Importance

Changes 0
Metric Value
cc 30
eloc 51
nc 392
nop 3
dl 0
loc 86
ccs 43
cts 50
cp 0.86
crap 32.4696
rs 0.9333
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
namespace PhpOffice\PhpSpreadsheet\Calculation;
4
5
use PhpOffice\PhpSpreadsheet\Shared\Date;
6
use PhpOffice\PhpSpreadsheet\Shared\StringHelper;
7
8
class DateTime
9
{
10
    /**
11
     * Identify if a year is a leap year or not.
12
     *
13
     * @param int|string $year The year to test
14
     *
15
     * @return bool TRUE if the year is a leap year, otherwise FALSE
16
     */
17 23
    public static function isLeapYear($year)
18
    {
19 23
        return (($year % 4) == 0) && (($year % 100) != 0) || (($year % 400) == 0);
20
    }
21
22
    /**
23
     * Return the number of days between two dates based on a 360 day calendar.
24
     *
25
     * @param int $startDay Day of month of the start date
26
     * @param int $startMonth Month of the start date
27
     * @param int $startYear Year of the start date
28
     * @param int $endDay Day of month of the start date
29
     * @param int $endMonth Month of the start date
30
     * @param int $endYear Year of the start date
31
     * @param bool $methodUS Whether to use the US method or the European method of calculation
32
     *
33
     * @return int Number of days between the start date and the end date
34
     */
35 69
    private static function dateDiff360($startDay, $startMonth, $startYear, $endDay, $endMonth, $endYear, $methodUS)
36
    {
37 69
        if ($startDay == 31) {
38 12
            --$startDay;
39 57
        } elseif ($methodUS && ($startMonth == 2 && ($startDay == 29 || ($startDay == 28 && !self::isLeapYear($startYear))))) {
40 1
            $startDay = 30;
41
        }
42 69
        if ($endDay == 31) {
43 21
            if ($methodUS && $startDay != 30) {
44 10
                $endDay = 1;
45 10
                if ($endMonth == 12) {
46 3
                    ++$endYear;
47 3
                    $endMonth = 1;
48
                } else {
49 10
                    ++$endMonth;
50
                }
51
            } else {
52 11
                $endDay = 30;
53
            }
54
        }
55
56 69
        return $endDay + $endMonth * 30 + $endYear * 360 - $startDay - $startMonth * 30 - $startYear * 360;
57
    }
58
59
    /**
60
     * getDateValue.
61
     *
62
     * @param string $dateValue
63
     *
64
     * @return mixed Excel date/time serial value, or string if error
65
     */
66 398
    public static function getDateValue($dateValue)
67
    {
68 398
        if (!is_numeric($dateValue)) {
69 362
            if ((is_string($dateValue)) &&
70 362
                (Functions::getCompatibilityMode() == Functions::COMPATIBILITY_GNUMERIC)) {
71
                return Functions::VALUE();
72
            }
73 362
            if ((is_object($dateValue)) && ($dateValue instanceof \DateTimeImmutable)) {
74
                $dateValue = Date::PHPToExcel($dateValue);
75
            } else {
76 362
                $saveReturnDateType = Functions::getReturnDateType();
77 362
                Functions::setReturnDateType(Functions::RETURNDATE_EXCEL);
78 362
                $dateValue = self::DATEVALUE($dateValue);
79 362
                Functions::setReturnDateType($saveReturnDateType);
80
            }
81
        }
82
83 398
        return $dateValue;
84
    }
85
86
    /**
87
     * getTimeValue.
88
     *
89
     * @param string $timeValue
90
     *
91
     * @return mixed Excel date/time serial value, or string if error
92
     */
93 12
    private static function getTimeValue($timeValue)
94
    {
95 12
        $saveReturnDateType = Functions::getReturnDateType();
96 12
        Functions::setReturnDateType(Functions::RETURNDATE_EXCEL);
97 12
        $timeValue = self::TIMEVALUE($timeValue);
98 12
        Functions::setReturnDateType($saveReturnDateType);
99
100 12
        return $timeValue;
101
    }
102
103 32
    private static function adjustDateByMonths($dateValue = 0, $adjustmentMonths = 0)
104
    {
105
        // Execute function
106 32
        $PHPDateObject = Date::excelToDateTimeObject($dateValue);
107 32
        $oMonth = (int) $PHPDateObject->format('m');
108 32
        $oYear = (int) $PHPDateObject->format('Y');
109
110 32
        $adjustmentMonthsString = (string) $adjustmentMonths;
111 32
        if ($adjustmentMonths > 0) {
112 15
            $adjustmentMonthsString = '+' . $adjustmentMonths;
113
        }
114 32
        if ($adjustmentMonths != 0) {
115 26
            $PHPDateObject->modify($adjustmentMonthsString . ' months');
116
        }
117 32
        $nMonth = (int) $PHPDateObject->format('m');
118 32
        $nYear = (int) $PHPDateObject->format('Y');
119
120 32
        $monthDiff = ($nMonth - $oMonth) + (($nYear - $oYear) * 12);
121 32
        if ($monthDiff != $adjustmentMonths) {
122 5
            $adjustDays = (int) $PHPDateObject->format('d');
123 5
            $adjustDaysString = '-' . $adjustDays . ' days';
124 5
            $PHPDateObject->modify($adjustDaysString);
125
        }
126
127 32
        return $PHPDateObject;
128
    }
129
130
    /**
131
     * DATETIMENOW.
132
     *
133
     * Returns the current date and time.
134
     * The NOW function is useful when you need to display the current date and time on a worksheet or
135
     * calculate a value based on the current date and time, and have that value updated each time you
136
     * open the worksheet.
137
     *
138
     * NOTE: When used in a Cell Formula, MS Excel changes the cell format so that it matches the date
139
     * and time format of your regional settings. PhpSpreadsheet does not change cell formatting in this way.
140
     *
141
     * Excel Function:
142
     *        NOW()
143
     *
144
     * @category Date/Time Functions
145
     *
146
     * @return mixed Excel date/time serial value, PHP date/time serial value or PHP date/time object,
147
     *                        depending on the value of the ReturnDateType flag
148
     */
149
    public static function DATETIMENOW()
150
    {
151
        $saveTimeZone = date_default_timezone_get();
152
        date_default_timezone_set('UTC');
153
        $retValue = false;
154
        switch (Functions::getReturnDateType()) {
155
            case Functions::RETURNDATE_EXCEL:
156
                $retValue = (float) Date::PHPToExcel(time());
157
158
                break;
159
            case Functions::RETURNDATE_PHP_NUMERIC:
160
                $retValue = (int) time();
161
162
                break;
163
            case Functions::RETURNDATE_PHP_OBJECT:
164
                $retValue = new \DateTime();
165
166
                break;
167
        }
168
        date_default_timezone_set($saveTimeZone);
169
170
        return $retValue;
171
    }
172
173
    /**
174
     * DATENOW.
175
     *
176
     * Returns the current date.
177
     * The NOW function is useful when you need to display the current date and time on a worksheet or
178
     * calculate a value based on the current date and time, and have that value updated each time you
179
     * open the worksheet.
180
     *
181
     * NOTE: When used in a Cell Formula, MS Excel changes the cell format so that it matches the date
182
     * and time format of your regional settings. PhpSpreadsheet does not change cell formatting in this way.
183
     *
184
     * Excel Function:
185
     *        TODAY()
186
     *
187
     * @category Date/Time Functions
188
     *
189
     * @return mixed Excel date/time serial value, PHP date/time serial value or PHP date/time object,
190
     *                        depending on the value of the ReturnDateType flag
191
     */
192 1
    public static function DATENOW()
193
    {
194 1
        $saveTimeZone = date_default_timezone_get();
195 1
        date_default_timezone_set('UTC');
196 1
        $retValue = false;
197 1
        $excelDateTime = floor(Date::PHPToExcel(time()));
198 1
        switch (Functions::getReturnDateType()) {
199
            case Functions::RETURNDATE_EXCEL:
200
                $retValue = (float) $excelDateTime;
201
202
                break;
203
            case Functions::RETURNDATE_PHP_NUMERIC:
204 1
                $retValue = (int) Date::excelToTimestamp($excelDateTime);
205
206 1
                break;
207
            case Functions::RETURNDATE_PHP_OBJECT:
208
                $retValue = Date::excelToDateTimeObject($excelDateTime);
209
210
                break;
211
        }
212 1
        date_default_timezone_set($saveTimeZone);
213
214 1
        return $retValue;
215
    }
216
217
    /**
218
     * DATE.
219
     *
220
     * The DATE function returns a value that represents a particular date.
221
     *
222
     * NOTE: When used in a Cell Formula, MS Excel changes the cell format so that it matches the date
223
     * format of your regional settings. PhpSpreadsheet does not change cell formatting in this way.
224
     *
225
     * Excel Function:
226
     *        DATE(year,month,day)
227
     *
228
     * PhpSpreadsheet is a lot more forgiving than MS Excel when passing non numeric values to this function.
229
     * A Month name or abbreviation (English only at this point) such as 'January' or 'Jan' will still be accepted,
230
     *     as will a day value with a suffix (e.g. '21st' rather than simply 21); again only English language.
231
     *
232
     * @category Date/Time Functions
233
     *
234
     * @param int $year The value of the year argument can include one to four digits.
235
     *                                Excel interprets the year argument according to the configured
236
     *                                date system: 1900 or 1904.
237
     *                                If year is between 0 (zero) and 1899 (inclusive), Excel adds that
238
     *                                value to 1900 to calculate the year. For example, DATE(108,1,2)
239
     *                                returns January 2, 2008 (1900+108).
240
     *                                If year is between 1900 and 9999 (inclusive), Excel uses that
241
     *                                value as the year. For example, DATE(2008,1,2) returns January 2,
242
     *                                2008.
243
     *                                If year is less than 0 or is 10000 or greater, Excel returns the
244
     *                                #NUM! error value.
245
     * @param int $month A positive or negative integer representing the month of the year
246
     *                                from 1 to 12 (January to December).
247
     *                                If month is greater than 12, month adds that number of months to
248
     *                                the first month in the year specified. For example, DATE(2008,14,2)
249
     *                                returns the serial number representing February 2, 2009.
250
     *                                If month is less than 1, month subtracts the magnitude of that
251
     *                                number of months, plus 1, from the first month in the year
252
     *                                specified. For example, DATE(2008,-3,2) returns the serial number
253
     *                                representing September 2, 2007.
254
     * @param int $day A positive or negative integer representing the day of the month
255
     *                                from 1 to 31.
256
     *                                If day is greater than the number of days in the month specified,
257
     *                                day adds that number of days to the first day in the month. For
258
     *                                example, DATE(2008,1,35) returns the serial number representing
259
     *                                February 4, 2008.
260
     *                                If day is less than 1, day subtracts the magnitude that number of
261
     *                                days, plus one, from the first day of the month specified. For
262
     *                                example, DATE(2008,1,-15) returns the serial number representing
263
     *                                December 16, 2007.
264
     *
265
     * @return mixed Excel date/time serial value, PHP date/time serial value or PHP date/time object,
266
     *                        depending on the value of the ReturnDateType flag
267
     */
268 84
    public static function DATE($year = 0, $month = 1, $day = 1)
269
    {
270 84
        $year = Functions::flattenSingleValue($year);
271 84
        $month = Functions::flattenSingleValue($month);
272 84
        $day = Functions::flattenSingleValue($day);
273
274 84
        if (($month !== null) && (!is_numeric($month))) {
275 3
            $month = Date::monthStringToNumber($month);
276
        }
277
278 84
        if (($day !== null) && (!is_numeric($day))) {
279 3
            $day = Date::dayStringToNumber($day);
280
        }
281
282 84
        $year = ($year !== null) ? StringHelper::testStringAsNumeric($year) : 0;
283 84
        $month = ($month !== null) ? StringHelper::testStringAsNumeric($month) : 0;
284 84
        $day = ($day !== null) ? StringHelper::testStringAsNumeric($day) : 0;
285 84
        if ((!is_numeric($year)) ||
286 83
            (!is_numeric($month)) ||
287 84
            (!is_numeric($day))) {
288 3
            return Functions::VALUE();
289
        }
290 81
        $year = (int) $year;
291 81
        $month = (int) $month;
292 81
        $day = (int) $day;
293
294 81
        $baseYear = Date::getExcelCalendar();
295
        // Validate parameters
296 81
        if ($year < ($baseYear - 1900)) {
297 2
            return Functions::NAN();
298
        }
299 79
        if ((($baseYear - 1900) != 0) && ($year < $baseYear) && ($year >= 1900)) {
300 1
            return Functions::NAN();
301
        }
302
303 78
        if (($year < $baseYear) && ($year >= ($baseYear - 1900))) {
304 7
            $year += 1900;
305
        }
306
307 78
        if ($month < 1) {
308
            //    Handle year/month adjustment if month < 1
309 22
            --$month;
310 22
            $year += ceil($month / 12) - 1;
311 22
            $month = 13 - abs($month % 12);
312 57
        } elseif ($month > 12) {
313
            //    Handle year/month adjustment if month > 12
314 8
            $year += floor($month / 12);
315 8
            $month = ($month % 12);
316
        }
317
318
        // Re-validate the year parameter after adjustments
319 78
        if (($year < $baseYear) || ($year >= 10000)) {
320 2
            return Functions::NAN();
321
        }
322
323
        // Execute function
324 76
        $excelDateValue = Date::formattedPHPToExcel($year, $month, $day);
2 ignored issues
show
Bug introduced by
It seems like $month can also be of type double; however, parameter $month of PhpOffice\PhpSpreadsheet...::formattedPHPToExcel() does only seem to accept integer, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

324
        $excelDateValue = Date::formattedPHPToExcel($year, /** @scrutinizer ignore-type */ $month, $day);
Loading history...
Bug introduced by
It seems like $year can also be of type double; however, parameter $year of PhpOffice\PhpSpreadsheet...::formattedPHPToExcel() does only seem to accept integer, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

324
        $excelDateValue = Date::formattedPHPToExcel(/** @scrutinizer ignore-type */ $year, $month, $day);
Loading history...
325 76
        switch (Functions::getReturnDateType()) {
326
            case Functions::RETURNDATE_EXCEL:
327 74
                return (float) $excelDateValue;
328
            case Functions::RETURNDATE_PHP_NUMERIC:
329 1
                return (int) Date::excelToTimestamp($excelDateValue);
330
            case Functions::RETURNDATE_PHP_OBJECT:
331 1
                return Date::excelToDateTimeObject($excelDateValue);
332
        }
333
    }
334
335
    /**
336
     * TIME.
337
     *
338
     * The TIME function returns a value that represents a particular time.
339
     *
340
     * NOTE: When used in a Cell Formula, MS Excel changes the cell format so that it matches the time
341
     * format of your regional settings. PhpSpreadsheet does not change cell formatting in this way.
342
     *
343
     * Excel Function:
344
     *        TIME(hour,minute,second)
345
     *
346
     * @category Date/Time Functions
347
     *
348
     * @param int $hour A number from 0 (zero) to 32767 representing the hour.
349
     *                                    Any value greater than 23 will be divided by 24 and the remainder
350
     *                                    will be treated as the hour value. For example, TIME(27,0,0) =
351
     *                                    TIME(3,0,0) = .125 or 3:00 AM.
352
     * @param int $minute A number from 0 to 32767 representing the minute.
353
     *                                    Any value greater than 59 will be converted to hours and minutes.
354
     *                                    For example, TIME(0,750,0) = TIME(12,30,0) = .520833 or 12:30 PM.
355
     * @param int $second A number from 0 to 32767 representing the second.
356
     *                                    Any value greater than 59 will be converted to hours, minutes,
357
     *                                    and seconds. For example, TIME(0,0,2000) = TIME(0,33,22) = .023148
358
     *                                    or 12:33:20 AM
359
     *
360
     * @return mixed Excel date/time serial value, PHP date/time serial value or PHP date/time object,
361
     *                        depending on the value of the ReturnDateType flag
362
     */
363 25
    public static function TIME($hour = 0, $minute = 0, $second = 0)
364
    {
365 25
        $hour = Functions::flattenSingleValue($hour);
366 25
        $minute = Functions::flattenSingleValue($minute);
367 25
        $second = Functions::flattenSingleValue($second);
368
369 25
        if ($hour == '') {
370 1
            $hour = 0;
371
        }
372 25
        if ($minute == '') {
373 6
            $minute = 0;
374
        }
375 25
        if ($second == '') {
376 6
            $second = 0;
377
        }
378
379 25
        if ((!is_numeric($hour)) || (!is_numeric($minute)) || (!is_numeric($second))) {
380 1
            return Functions::VALUE();
381
        }
382 24
        $hour = (int) $hour;
383 24
        $minute = (int) $minute;
384 24
        $second = (int) $second;
385
386 24
        if ($second < 0) {
387 5
            $minute += floor($second / 60);
388 5
            $second = 60 - abs($second % 60);
389 5
            if ($second == 60) {
390 5
                $second = 0;
391
            }
392 20
        } elseif ($second >= 60) {
393 1
            $minute += floor($second / 60);
394 1
            $second = $second % 60;
395
        }
396 24
        if ($minute < 0) {
397 8
            $hour += floor($minute / 60);
398 8
            $minute = 60 - abs($minute % 60);
399 8
            if ($minute == 60) {
400 8
                $minute = 0;
401
            }
402 17
        } elseif ($minute >= 60) {
403 3
            $hour += floor($minute / 60);
404 3
            $minute = $minute % 60;
405
        }
406
407 24
        if ($hour > 23) {
408 1
            $hour = $hour % 24;
409 23
        } elseif ($hour < 0) {
410 3
            return Functions::NAN();
411
        }
412
413
        // Execute function
414 22
        switch (Functions::getReturnDateType()) {
415
            case Functions::RETURNDATE_EXCEL:
416 20
                $date = 0;
417 20
                $calendar = Date::getExcelCalendar();
418 20
                if ($calendar != Date::CALENDAR_WINDOWS_1900) {
419
                    $date = 1;
420
                }
421
422 20
                return (float) Date::formattedPHPToExcel($calendar, 1, $date, $hour, $minute, $second);
3 ignored issues
show
Bug introduced by
It seems like $hour can also be of type double; however, parameter $hours of PhpOffice\PhpSpreadsheet...::formattedPHPToExcel() does only seem to accept integer, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

422
                return (float) Date::formattedPHPToExcel($calendar, 1, $date, /** @scrutinizer ignore-type */ $hour, $minute, $second);
Loading history...
Bug introduced by
It seems like $second can also be of type double; however, parameter $seconds of PhpOffice\PhpSpreadsheet...::formattedPHPToExcel() does only seem to accept integer, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

422
                return (float) Date::formattedPHPToExcel($calendar, 1, $date, $hour, $minute, /** @scrutinizer ignore-type */ $second);
Loading history...
Bug introduced by
It seems like $minute can also be of type double; however, parameter $minutes of PhpOffice\PhpSpreadsheet...::formattedPHPToExcel() does only seem to accept integer, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

422
                return (float) Date::formattedPHPToExcel($calendar, 1, $date, $hour, /** @scrutinizer ignore-type */ $minute, $second);
Loading history...
423
            case Functions::RETURNDATE_PHP_NUMERIC:
424 1
                return (int) Date::excelToTimestamp(Date::formattedPHPToExcel(1970, 1, 1, $hour, $minute, $second)); // -2147468400; //    -2147472000 + 3600
425
            case Functions::RETURNDATE_PHP_OBJECT:
426 1
                $dayAdjust = 0;
427 1
                if ($hour < 0) {
428
                    $dayAdjust = floor($hour / 24);
429
                    $hour = 24 - abs($hour % 24);
430
                    if ($hour == 24) {
431
                        $hour = 0;
432
                    }
433 1
                } elseif ($hour >= 24) {
434
                    $dayAdjust = floor($hour / 24);
435
                    $hour = $hour % 24;
436
                }
437 1
                $phpDateObject = new \DateTime('1900-01-01 ' . $hour . ':' . $minute . ':' . $second);
438 1
                if ($dayAdjust != 0) {
439
                    $phpDateObject->modify($dayAdjust . ' days');
440
                }
441
442 1
                return $phpDateObject;
443
        }
444
    }
445
446
    /**
447
     * DATEVALUE.
448
     *
449
     * Returns a value that represents a particular date.
450
     * Use DATEVALUE to convert a date represented by a text string to an Excel or PHP date/time stamp
451
     * value.
452
     *
453
     * NOTE: When used in a Cell Formula, MS Excel changes the cell format so that it matches the date
454
     * format of your regional settings. PhpSpreadsheet does not change cell formatting in this way.
455
     *
456
     * Excel Function:
457
     *        DATEVALUE(dateValue)
458
     *
459
     * @category Date/Time Functions
460
     *
461
     * @param string $dateValue Text that represents a date in a Microsoft Excel date format.
462
     *                                    For example, "1/30/2008" or "30-Jan-2008" are text strings within
463
     *                                    quotation marks that represent dates. Using the default date
464
     *                                    system in Excel for Windows, date_text must represent a date from
465
     *                                    January 1, 1900, to December 31, 9999. Using the default date
466
     *                                    system in Excel for the Macintosh, date_text must represent a date
467
     *                                    from January 1, 1904, to December 31, 9999. DATEVALUE returns the
468
     *                                    #VALUE! error value if date_text is out of this range.
469
     *
470
     * @return mixed Excel date/time serial value, PHP date/time serial value or PHP date/time object,
471
     *                        depending on the value of the ReturnDateType flag
472
     */
473 439
    public static function DATEVALUE($dateValue = 1)
474
    {
475 439
        $dateValueOrig = $dateValue;
0 ignored issues
show
Unused Code introduced by
The assignment to $dateValueOrig is dead and can be removed.
Loading history...
476 439
        $dateValue = trim(Functions::flattenSingleValue($dateValue), '"');
477
        //    Strip any ordinals because they're allowed in Excel (English only)
478 439
        $dateValue = preg_replace('/(\d)(st|nd|rd|th)([ -\/])/Ui', '$1$3', $dateValue);
479
        //    Convert separators (/ . or space) to hyphens (should also handle dot used for ordinals in some countries, e.g. Denmark, Germany)
480 439
        $dateValue = str_replace(['/', '.', '-', '  '], ' ', $dateValue);
481
482 439
        $yearFound = false;
483 439
        $t1 = explode(' ', $dateValue);
484 439
        foreach ($t1 as &$t) {
485 439
            if ((is_numeric($t)) && ($t > 31)) {
486 405
                if ($yearFound) {
487
                    return Functions::VALUE();
488
                }
489 405
                if ($t < 100) {
490 2
                    $t += 1900;
491
                }
492 439
                $yearFound = true;
493
            }
494
        }
495 439
        if ((count($t1) == 1) && (strpos($t, ':') != false)) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $t seems to be defined by a foreach iteration on line 484. Are you sure the iterator is never empty, otherwise this variable is not defined?
Loading history...
Bug Best Practice introduced by
It seems like you are loosely comparing strpos($t, ':') of type integer to the boolean false. If you are specifically checking for non-zero, consider using something more explicit like > 0 or !== 0 instead.
Loading history...
496
            //    We've been fed a time value without any date
497 1
            return 0.0;
498 438
        } elseif (count($t1) == 2) {
499
            //    We only have two parts of the date: either day/month or month/year
500 28
            if ($yearFound) {
501 4
                array_unshift($t1, 1);
502
            } else {
503 25
                if ($t1[1] > 29) {
504 1
                    $t1[1] += 1900;
505 1
                    array_unshift($t1, 1);
506
                } else {
507 24
                    $t1[] = date('Y');
508
                }
509
            }
510
        }
511 438
        unset($t);
512 438
        $dateValue = implode(' ', $t1);
513
514 438
        $PHPDateArray = date_parse($dateValue);
515 438
        if (($PHPDateArray === false) || ($PHPDateArray['error_count'] > 0)) {
516 326
            $testVal1 = strtok($dateValue, '- ');
517 326
            if ($testVal1 !== false) {
518 325
                $testVal2 = strtok('- ');
519 325
                if ($testVal2 !== false) {
520 310
                    $testVal3 = strtok('- ');
521 310
                    if ($testVal3 === false) {
522 310
                        $testVal3 = strftime('%Y');
523
                    }
524
                } else {
525 325
                    return Functions::VALUE();
526
                }
527
            } else {
528 1
                return Functions::VALUE();
529
            }
530 310
            if ($testVal1 < 31 && $testVal2 < 12 && $testVal3 < 12 && strlen($testVal3) == 2) {
531 2
                $testVal3 += 2000;
532
            }
533 310
            $PHPDateArray = date_parse($testVal1 . '-' . $testVal2 . '-' . $testVal3);
534 310
            if (($PHPDateArray === false) || ($PHPDateArray['error_count'] > 0)) {
535 26
                $PHPDateArray = date_parse($testVal2 . '-' . $testVal1 . '-' . $testVal3);
536 26
                if (($PHPDateArray === false) || ($PHPDateArray['error_count'] > 0)) {
537 22
                    return Functions::VALUE();
538
                }
539
            }
540
        }
541
542 406
        if (($PHPDateArray !== false) && ($PHPDateArray['error_count'] == 0)) {
543
            // Execute function
544 406
            if ($PHPDateArray['year'] == '') {
545
                $PHPDateArray['year'] = strftime('%Y');
546
            }
547 406
            if ($PHPDateArray['year'] < 1900) {
548 3
                return Functions::VALUE();
549
            }
550 403
            if ($PHPDateArray['month'] == '') {
551
                $PHPDateArray['month'] = strftime('%m');
552
            }
553 403
            if ($PHPDateArray['day'] == '') {
554
                $PHPDateArray['day'] = strftime('%d');
555
            }
556 403
            if (!checkdate($PHPDateArray['month'], $PHPDateArray['day'], $PHPDateArray['year'])) {
557 4
                return Functions::VALUE();
558
            }
559 400
            $excelDateValue = floor(
560 400
                Date::formattedPHPToExcel(
561 400
                    $PHPDateArray['year'],
562 400
                    $PHPDateArray['month'],
563 400
                    $PHPDateArray['day'],
564 400
                    $PHPDateArray['hour'],
565 400
                    $PHPDateArray['minute'],
566 400
                    $PHPDateArray['second']
567
                )
568
            );
569 400
            switch (Functions::getReturnDateType()) {
570 2
                case Functions::RETURNDATE_EXCEL:
571 398
                    return (float) $excelDateValue;
572
                case Functions::RETURNDATE_PHP_NUMERIC:
573 1
                    return (int) Date::excelToTimestamp($excelDateValue);
574
                case Functions::RETURNDATE_PHP_OBJECT:
575 1
                    return new \DateTime($PHPDateArray['year'] . '-' . $PHPDateArray['month'] . '-' . $PHPDateArray['day'] . ' 00:00:00');
576
            }
577
        }
578
579
        return Functions::VALUE();
580
    }
581
582
    /**
583
     * TIMEVALUE.
584
     *
585
     * Returns a value that represents a particular time.
586
     * Use TIMEVALUE to convert a time represented by a text string to an Excel or PHP date/time stamp
587
     * value.
588
     *
589
     * NOTE: When used in a Cell Formula, MS Excel changes the cell format so that it matches the time
590
     * format of your regional settings. PhpSpreadsheet does not change cell formatting in this way.
591
     *
592
     * Excel Function:
593
     *        TIMEVALUE(timeValue)
594
     *
595
     * @category Date/Time Functions
596
     *
597
     * @param string $timeValue A text string that represents a time in any one of the Microsoft
598
     *                                    Excel time formats; for example, "6:45 PM" and "18:45" text strings
599
     *                                    within quotation marks that represent time.
600
     *                                    Date information in time_text is ignored.
601
     *
602
     * @return mixed Excel date/time serial value, PHP date/time serial value or PHP date/time object,
603
     *                        depending on the value of the ReturnDateType flag
604
     */
605 31
    public static function TIMEVALUE($timeValue)
606
    {
607 31
        $timeValue = trim(Functions::flattenSingleValue($timeValue), '"');
608 31
        $timeValue = str_replace(['/', '.'], '-', $timeValue);
609
610 31
        $arraySplit = preg_split('/[\/:\-\s]/', $timeValue);
611 31
        if ((count($arraySplit) == 2 || count($arraySplit) == 3) && $arraySplit[0] > 24) {
1 ignored issue
show
Bug introduced by
It seems like $arraySplit can also be of type false; however, parameter $var of count() does only seem to accept Countable|array, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

611
        if ((count(/** @scrutinizer ignore-type */ $arraySplit) == 2 || count($arraySplit) == 3) && $arraySplit[0] > 24) {
Loading history...
612 1
            $arraySplit[0] = ($arraySplit[0] % 24);
613 1
            $timeValue = implode(':', $arraySplit);
1 ignored issue
show
Bug introduced by
It seems like $arraySplit can also be of type false; however, parameter $pieces of implode() does only seem to accept array, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

613
            $timeValue = implode(':', /** @scrutinizer ignore-type */ $arraySplit);
Loading history...
614
        }
615
616 31
        $PHPDateArray = date_parse($timeValue);
617 31
        if (($PHPDateArray !== false) && ($PHPDateArray['error_count'] == 0)) {
618 26
            if (Functions::getCompatibilityMode() == Functions::COMPATIBILITY_OPENOFFICE) {
619
                $excelDateValue = Date::formattedPHPToExcel(
620
                    $PHPDateArray['year'],
621
                    $PHPDateArray['month'],
622
                    $PHPDateArray['day'],
623
                    $PHPDateArray['hour'],
624
                    $PHPDateArray['minute'],
625
                    $PHPDateArray['second']
626
                );
627
            } else {
628 26
                $excelDateValue = Date::formattedPHPToExcel(1900, 1, 1, $PHPDateArray['hour'], $PHPDateArray['minute'], $PHPDateArray['second']) - 1;
629
            }
630
631 26
            switch (Functions::getReturnDateType()) {
632 1
                case Functions::RETURNDATE_EXCEL:
633 24
                    return (float) $excelDateValue;
634
                case Functions::RETURNDATE_PHP_NUMERIC:
635 1
                    return (int) $phpDateValue = Date::excelToTimestamp($excelDateValue + 25569) - 3600;
0 ignored issues
show
Unused Code introduced by
The assignment to $phpDateValue is dead and can be removed.
Loading history...
636
                case Functions::RETURNDATE_PHP_OBJECT:
637 1
                    return new \DateTime('1900-01-01 ' . $PHPDateArray['hour'] . ':' . $PHPDateArray['minute'] . ':' . $PHPDateArray['second']);
638
            }
639
        }
640
641 6
        return Functions::VALUE();
642
    }
643
644
    /**
645
     * DATEDIF.
646
     *
647
     * @param mixed $startDate Excel date serial value, PHP date/time stamp, PHP DateTime object
648
     *                                    or a standard date string
649
     * @param mixed $endDate Excel date serial value, PHP date/time stamp, PHP DateTime object
650
     *                                    or a standard date string
651
     * @param string $unit
652
     *
653
     * @return int|string Interval between the dates
654
     */
655 151
    public static function DATEDIF($startDate = 0, $endDate = 0, $unit = 'D')
656
    {
657 151
        $startDate = Functions::flattenSingleValue($startDate);
658 151
        $endDate = Functions::flattenSingleValue($endDate);
659 151
        $unit = strtoupper(Functions::flattenSingleValue($unit));
660
661 151
        if (is_string($startDate = self::getDateValue($startDate))) {
662 1
            return Functions::VALUE();
663
        }
664 150
        if (is_string($endDate = self::getDateValue($endDate))) {
665 1
            return Functions::VALUE();
666
        }
667
668
        // Validate parameters
669 149
        if ($startDate > $endDate) {
670 1
            return Functions::NAN();
671
        }
672
673
        // Execute function
674 148
        $difference = $endDate - $startDate;
675
676 148
        $PHPStartDateObject = Date::excelToDateTimeObject($startDate);
677 148
        $startDays = $PHPStartDateObject->format('j');
678 148
        $startMonths = $PHPStartDateObject->format('n');
679 148
        $startYears = $PHPStartDateObject->format('Y');
680
681 148
        $PHPEndDateObject = Date::excelToDateTimeObject($endDate);
682 148
        $endDays = $PHPEndDateObject->format('j');
683 148
        $endMonths = $PHPEndDateObject->format('n');
684 148
        $endYears = $PHPEndDateObject->format('Y');
685
686 148
        $retVal = Functions::NAN();
0 ignored issues
show
Unused Code introduced by
The assignment to $retVal is dead and can be removed.
Loading history...
687 148
        switch ($unit) {
688 148
            case 'D':
689 65
                $retVal = (int) $difference;
690
691 65
                break;
692 83
            case 'M':
693 15
                $retVal = (int) ($endMonths - $startMonths) + ((int) ($endYears - $startYears) * 12);
694
                //    We're only interested in full months
695 15
                if ($endDays < $startDays) {
696 3
                    --$retVal;
697
                }
698
699 15
                break;
700 68
            case 'Y':
701 17
                $retVal = (int) ($endYears - $startYears);
702
                //    We're only interested in full months
703 17
                if ($endMonths < $startMonths) {
704 5
                    --$retVal;
705 12
                } elseif (($endMonths == $startMonths) && ($endDays < $startDays)) {
706
                    // Remove start month
707 1
                    --$retVal;
708
                    // Remove end month
709 1
                    --$retVal;
710
                }
711
712 17
                break;
713 51
            case 'MD':
714 15
                if ($endDays < $startDays) {
715 3
                    $retVal = $endDays;
716 3
                    $PHPEndDateObject->modify('-' . $endDays . ' days');
717 3
                    $adjustDays = $PHPEndDateObject->format('j');
718 3
                    $retVal += ($adjustDays - $startDays);
719
                } else {
720 12
                    $retVal = $endDays - $startDays;
721
                }
722
723 15
                break;
724 36
            case 'YM':
725 15
                $retVal = (int) ($endMonths - $startMonths);
726 15
                if ($retVal < 0) {
727 4
                    $retVal += 12;
728
                }
729
                //    We're only interested in full months
730 15
                if ($endDays < $startDays) {
731 3
                    --$retVal;
732
                }
733
734 15
                break;
735 21
            case 'YD':
736 20
                $retVal = (int) $difference;
737 20
                if ($endYears > $startYears) {
738 9
                    $isLeapStartYear = $PHPStartDateObject->format('L');
739 9
                    $wasLeapEndYear = $PHPEndDateObject->format('L');
740
741
                    // Adjust end year to be as close as possible as start year
742 9
                    while ($PHPEndDateObject >= $PHPStartDateObject) {
743 9
                        $PHPEndDateObject->modify('-1 year');
744 9
                        $endYears = $PHPEndDateObject->format('Y');
0 ignored issues
show
Unused Code introduced by
The assignment to $endYears is dead and can be removed.
Loading history...
745
                    }
746 9
                    $PHPEndDateObject->modify('+1 year');
747
748
                    // Get the result
749 9
                    $retVal = $PHPEndDateObject->diff($PHPStartDateObject)->days;
750
751
                    // Adjust for leap years cases
752 9
                    $isLeapEndYear = $PHPEndDateObject->format('L');
753 9
                    $limit = new \DateTime($PHPEndDateObject->format('Y-02-29'));
754 9
                    if (!$isLeapStartYear && !$wasLeapEndYear && $isLeapEndYear && $PHPEndDateObject >= $limit) {
755 1
                        --$retVal;
756
                    }
757
                }
758
759 20
                break;
760
            default:
761 1
                $retVal = Functions::VALUE();
762
        }
763
764 148
        return $retVal;
765
    }
766
767
    /**
768
     * DAYS360.
769
     *
770
     * Returns the number of days between two dates based on a 360-day year (twelve 30-day months),
771
     * which is used in some accounting calculations. Use this function to help compute payments if
772
     * your accounting system is based on twelve 30-day months.
773
     *
774
     * Excel Function:
775
     *        DAYS360(startDate,endDate[,method])
776
     *
777
     * @category Date/Time Functions
778
     *
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 bool $method US or European Method
784
     *                                        FALSE or omitted: U.S. (NASD) method. If the starting date is
785
     *                                        the last day of a month, it becomes equal to the 30th of the
786
     *                                        same month. If the ending date is the last day of a month and
787
     *                                        the starting date is earlier than the 30th of a month, the
788
     *                                        ending date becomes equal to the 1st of the next month;
789
     *                                        otherwise the ending date becomes equal to the 30th of the
790
     *                                        same month.
791
     *                                        TRUE: European method. Starting dates and ending dates that
792
     *                                        occur on the 31st of a month become equal to the 30th of the
793
     *                                        same month.
794
     *
795
     * @return int|string Number of days between start date and end date
796
     */
797 73
    public static function DAYS360($startDate = 0, $endDate = 0, $method = false)
798
    {
799 73
        $startDate = Functions::flattenSingleValue($startDate);
800 73
        $endDate = Functions::flattenSingleValue($endDate);
801
802 73
        if (is_string($startDate = self::getDateValue($startDate))) {
803 1
            return Functions::VALUE();
804
        }
805 72
        if (is_string($endDate = self::getDateValue($endDate))) {
806 1
            return Functions::VALUE();
807
        }
808
809 71
        if (!is_bool($method)) {
0 ignored issues
show
introduced by
The condition is_bool($method) is always true.
Loading history...
810 2
            return Functions::VALUE();
811
        }
812
813
        // Execute function
814 69
        $PHPStartDateObject = Date::excelToDateTimeObject($startDate);
815 69
        $startDay = $PHPStartDateObject->format('j');
816 69
        $startMonth = $PHPStartDateObject->format('n');
817 69
        $startYear = $PHPStartDateObject->format('Y');
818
819 69
        $PHPEndDateObject = Date::excelToDateTimeObject($endDate);
820 69
        $endDay = $PHPEndDateObject->format('j');
821 69
        $endMonth = $PHPEndDateObject->format('n');
822 69
        $endYear = $PHPEndDateObject->format('Y');
823
824 69
        return self::dateDiff360($startDay, $startMonth, $startYear, $endDay, $endMonth, $endYear, !$method);
0 ignored issues
show
Bug introduced by
$startMonth of type string is incompatible with the type integer expected by parameter $startMonth of PhpOffice\PhpSpreadsheet...DateTime::dateDiff360(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

824
        return self::dateDiff360($startDay, /** @scrutinizer ignore-type */ $startMonth, $startYear, $endDay, $endMonth, $endYear, !$method);
Loading history...
Bug introduced by
$endDay of type string is incompatible with the type integer expected by parameter $endDay of PhpOffice\PhpSpreadsheet...DateTime::dateDiff360(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

824
        return self::dateDiff360($startDay, $startMonth, $startYear, /** @scrutinizer ignore-type */ $endDay, $endMonth, $endYear, !$method);
Loading history...
Bug introduced by
$startDay of type string is incompatible with the type integer expected by parameter $startDay of PhpOffice\PhpSpreadsheet...DateTime::dateDiff360(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

824
        return self::dateDiff360(/** @scrutinizer ignore-type */ $startDay, $startMonth, $startYear, $endDay, $endMonth, $endYear, !$method);
Loading history...
Bug introduced by
$endMonth of type string is incompatible with the type integer expected by parameter $endMonth of PhpOffice\PhpSpreadsheet...DateTime::dateDiff360(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

824
        return self::dateDiff360($startDay, $startMonth, $startYear, $endDay, /** @scrutinizer ignore-type */ $endMonth, $endYear, !$method);
Loading history...
Bug introduced by
$startYear of type string is incompatible with the type integer expected by parameter $startYear of PhpOffice\PhpSpreadsheet...DateTime::dateDiff360(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

824
        return self::dateDiff360($startDay, $startMonth, /** @scrutinizer ignore-type */ $startYear, $endDay, $endMonth, $endYear, !$method);
Loading history...
Bug introduced by
$endYear of type string is incompatible with the type integer expected by parameter $endYear of PhpOffice\PhpSpreadsheet...DateTime::dateDiff360(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

824
        return self::dateDiff360($startDay, $startMonth, $startYear, $endDay, $endMonth, /** @scrutinizer ignore-type */ $endYear, !$method);
Loading history...
825
    }
826
827
    /**
828
     * YEARFRAC.
829
     *
830
     * Calculates the fraction of the year represented by the number of whole days between two dates
831
     * (the start_date and the end_date).
832
     * Use the YEARFRAC worksheet function to identify the proportion of a whole year's benefits or
833
     * obligations to assign to a specific term.
834
     *
835
     * Excel Function:
836
     *        YEARFRAC(startDate,endDate[,method])
837
     *
838
     * @category Date/Time Functions
839
     *
840
     * @param mixed $startDate Excel date serial value (float), PHP date timestamp (integer),
841
     *                                    PHP DateTime object, or a standard date string
842
     * @param mixed $endDate Excel date serial value (float), PHP date timestamp (integer),
843
     *                                    PHP DateTime object, or a standard date string
844
     * @param int $method Method used for the calculation
845
     *                                        0 or omitted    US (NASD) 30/360
846
     *                                        1                Actual/actual
847
     *                                        2                Actual/360
848
     *                                        3                Actual/365
849
     *                                        4                European 30/360
850
     *
851
     * @return float fraction of the year
852
     */
853 91
    public static function YEARFRAC($startDate = 0, $endDate = 0, $method = 0)
854
    {
855 91
        $startDate = Functions::flattenSingleValue($startDate);
856 91
        $endDate = Functions::flattenSingleValue($endDate);
857 91
        $method = Functions::flattenSingleValue($method);
858
859 91
        if (is_string($startDate = self::getDateValue($startDate))) {
860 4
            return Functions::VALUE();
0 ignored issues
show
Bug Best Practice introduced by
The expression return PhpOffice\PhpSpre...tion\Functions::VALUE() returns the type string which is incompatible with the documented return type double.
Loading history...
861
        }
862 87
        if (is_string($endDate = self::getDateValue($endDate))) {
863
            return Functions::VALUE();
0 ignored issues
show
Bug Best Practice introduced by
The expression return PhpOffice\PhpSpre...tion\Functions::VALUE() returns the type string which is incompatible with the documented return type double.
Loading history...
864
        }
865
866 87
        if (((is_numeric($method)) && (!is_string($method))) || ($method == '')) {
867 86
            switch ($method) {
868 86
                case 0:
869 23
                    return self::DAYS360($startDate, $endDate) / 360;
870 63
                case 1:
871 20
                    $days = self::DATEDIF($startDate, $endDate);
872 20
                    $startYear = self::YEAR($startDate);
873 20
                    $endYear = self::YEAR($endDate);
874 20
                    $years = $endYear - $startYear + 1;
875 20
                    $leapDays = 0;
876 20
                    if ($years == 1) {
877 14
                        if (self::isLeapYear($endYear)) {
878 4
                            $startMonth = self::MONTHOFYEAR($startDate);
879 4
                            $endMonth = self::MONTHOFYEAR($endDate);
880 4
                            $endDay = self::DAYOFMONTH($endDate);
881 4
                            if (($startMonth < 3) ||
882 4
                                (($endMonth * 100 + $endDay) >= (2 * 100 + 29))) {
883 14
                                $leapDays += 1;
884
                            }
885
                        }
886
                    } else {
887 6
                        for ($year = $startYear; $year <= $endYear; ++$year) {
888 6
                            if ($year == $startYear) {
889 6
                                $startMonth = self::MONTHOFYEAR($startDate);
890 6
                                $startDay = self::DAYOFMONTH($startDate);
0 ignored issues
show
Unused Code introduced by
The assignment to $startDay is dead and can be removed.
Loading history...
891 6
                                if ($startMonth < 3) {
892 6
                                    $leapDays += (self::isLeapYear($year)) ? 1 : 0;
893
                                }
894 6
                            } elseif ($year == $endYear) {
895 6
                                $endMonth = self::MONTHOFYEAR($endDate);
896 6
                                $endDay = self::DAYOFMONTH($endDate);
897 6
                                if (($endMonth * 100 + $endDay) >= (2 * 100 + 29)) {
898 6
                                    $leapDays += (self::isLeapYear($year)) ? 1 : 0;
899
                                }
900
                            } else {
901 2
                                $leapDays += (self::isLeapYear($year)) ? 1 : 0;
902
                            }
903
                        }
904 6
                        if ($years == 2) {
905 4
                            if (($leapDays == 0) && (self::isLeapYear($startYear)) && ($days > 365)) {
906
                                $leapDays = 1;
907 4
                            } elseif ($days < 366) {
908 1
                                $years = 1;
909
                            }
910
                        }
911 6
                        $leapDays /= $years;
912
                    }
913
914 20
                    return $days / (365 + $leapDays);
915 43
                case 2:
916 14
                    return self::DATEDIF($startDate, $endDate) / 360;
917 29
                case 3:
918 14
                    return self::DATEDIF($startDate, $endDate) / 365;
919 15
                case 4:
920 15
                    return self::DAYS360($startDate, $endDate, true) / 360;
921
            }
922
        }
923
924 1
        return Functions::VALUE();
0 ignored issues
show
Bug Best Practice introduced by
The expression return PhpOffice\PhpSpre...tion\Functions::VALUE() returns the type string which is incompatible with the documented return type double.
Loading history...
925
    }
926
927
    /**
928
     * NETWORKDAYS.
929
     *
930
     * Returns the number of whole working days between start_date and end_date. Working days
931
     * exclude weekends and any dates identified in holidays.
932
     * Use NETWORKDAYS to calculate employee benefits that accrue based on the number of days
933
     * worked during a specific term.
934
     *
935
     * Excel Function:
936
     *        NETWORKDAYS(startDate,endDate[,holidays[,holiday[,...]]])
937
     *
938
     * @category Date/Time Functions
939
     *
940
     * @param mixed $startDate Excel date serial value (float), PHP date timestamp (integer),
941
     *                                            PHP DateTime object, or a standard date string
942
     * @param mixed $endDate Excel date serial value (float), PHP date timestamp (integer),
943
     *                                            PHP DateTime object, or a standard date string
944
     *
945
     * @return int|string Interval between the dates
946
     */
947 18
    public static function NETWORKDAYS($startDate, $endDate, ...$dateArgs)
948
    {
949
        //    Retrieve the mandatory start and end date that are referenced in the function definition
950 18
        $startDate = Functions::flattenSingleValue($startDate);
951 18
        $endDate = Functions::flattenSingleValue($endDate);
952
        //    Get the optional days
953 18
        $dateArgs = Functions::flattenArray($dateArgs);
954
955
        //    Validate the start and end dates
956 18
        if (is_string($startDate = $sDate = self::getDateValue($startDate))) {
957
            return Functions::VALUE();
958
        }
959 18
        $startDate = (float) floor($startDate);
960 18
        if (is_string($endDate = $eDate = self::getDateValue($endDate))) {
961
            return Functions::VALUE();
962
        }
963 18
        $endDate = (float) floor($endDate);
964
965 18
        if ($sDate > $eDate) {
966 2
            $startDate = $eDate;
967 2
            $endDate = $sDate;
968
        }
969
970
        // Execute function
971 18
        $startDoW = 6 - self::WEEKDAY($startDate, 2);
972 18
        if ($startDoW < 0) {
973
            $startDoW = 0;
974
        }
975 18
        $endDoW = self::WEEKDAY($endDate, 2);
976 18
        if ($endDoW >= 6) {
977 2
            $endDoW = 0;
978
        }
979
980 18
        $wholeWeekDays = floor(($endDate - $startDate) / 7) * 5;
981 18
        $partWeekDays = $endDoW + $startDoW;
982 18
        if ($partWeekDays > 5) {
983 14
            $partWeekDays -= 5;
984
        }
985
986
        //    Test any extra holiday parameters
987 18
        $holidayCountedArray = [];
988 18
        foreach ($dateArgs as $holidayDate) {
989 4
            if (is_string($holidayDate = self::getDateValue($holidayDate))) {
990
                return Functions::VALUE();
991
            }
992 4
            if (($holidayDate >= $startDate) && ($holidayDate <= $endDate)) {
993 4
                if ((self::WEEKDAY($holidayDate, 2) < 6) && (!in_array($holidayDate, $holidayCountedArray))) {
994 4
                    --$partWeekDays;
995 4
                    $holidayCountedArray[] = $holidayDate;
996
                }
997
            }
998
        }
999
1000 18
        if ($sDate > $eDate) {
1001 2
            return 0 - ($wholeWeekDays + $partWeekDays);
1002
        }
1003
1004 16
        return $wholeWeekDays + $partWeekDays;
1005
    }
1006
1007
    /**
1008
     * WORKDAY.
1009
     *
1010
     * Returns the date that is the indicated number of working days before or after a date (the
1011
     * starting date). Working days exclude weekends and any dates identified as holidays.
1012
     * Use WORKDAY to exclude weekends or holidays when you calculate invoice due dates, expected
1013
     * delivery times, or the number of days of work performed.
1014
     *
1015
     * Excel Function:
1016
     *        WORKDAY(startDate,endDays[,holidays[,holiday[,...]]])
1017
     *
1018
     * @category Date/Time Functions
1019
     *
1020
     * @param mixed $startDate Excel date serial value (float), PHP date timestamp (integer),
1021
     *                                        PHP DateTime object, or a standard date string
1022
     * @param int $endDays The number of nonweekend and nonholiday days before or after
1023
     *                                        startDate. A positive value for days yields a future date; a
1024
     *                                        negative value yields a past date.
1025
     *
1026
     * @return mixed Excel date/time serial value, PHP date/time serial value or PHP date/time object,
1027
     *                        depending on the value of the ReturnDateType flag
1028
     */
1029 13
    public static function WORKDAY($startDate, $endDays, ...$dateArgs)
1030
    {
1031
        //    Retrieve the mandatory start date and days that are referenced in the function definition
1032 13
        $startDate = Functions::flattenSingleValue($startDate);
1033 13
        $endDays = Functions::flattenSingleValue($endDays);
1034
        //    Get the optional days
1035 13
        $dateArgs = Functions::flattenArray($dateArgs);
1036
1037 13
        if ((is_string($startDate = self::getDateValue($startDate))) || (!is_numeric($endDays))) {
1038 1
            return Functions::VALUE();
1039
        }
1040 12
        $startDate = (float) floor($startDate);
1041 12
        $endDays = (int) floor($endDays);
1042
        //    If endDays is 0, we always return startDate
1043 12
        if ($endDays == 0) {
1044
            return $startDate;
1045
        }
1046
1047 12
        $decrementing = ($endDays < 0) ? true : false;
1048
1049
        //    Adjust the start date if it falls over a weekend
1050
1051 12
        $startDoW = self::WEEKDAY($startDate, 3);
0 ignored issues
show
Bug introduced by
$startDate of type double is incompatible with the type integer expected by parameter $dateValue of PhpOffice\PhpSpreadsheet...ion\DateTime::WEEKDAY(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

1051
        $startDoW = self::WEEKDAY(/** @scrutinizer ignore-type */ $startDate, 3);
Loading history...
1052 12
        if (self::WEEKDAY($startDate, 3) >= 5) {
1053 4
            $startDate += ($decrementing) ? -$startDoW + 4 : 7 - $startDoW;
1054 4
            ($decrementing) ? $endDays++ : $endDays--;
1055
        }
1056
1057
        //    Add endDays
1058 12
        $endDate = (float) $startDate + ((int) ($endDays / 5) * 7) + ($endDays % 5);
1059
1060
        //    Adjust the calculated end date if it falls over a weekend
1061 12
        $endDoW = self::WEEKDAY($endDate, 3);
1062 12
        if ($endDoW >= 5) {
1063 1
            $endDate += ($decrementing) ? -$endDoW + 4 : 7 - $endDoW;
1064
        }
1065
1066
        //    Test any extra holiday parameters
1067 12
        if (!empty($dateArgs)) {
1068 4
            $holidayCountedArray = $holidayDates = [];
1069 4
            foreach ($dateArgs as $holidayDate) {
1070 4
                if (($holidayDate !== null) && (trim($holidayDate) > '')) {
1071 4
                    if (is_string($holidayDate = self::getDateValue($holidayDate))) {
1072
                        return Functions::VALUE();
1073
                    }
1074 4
                    if (self::WEEKDAY($holidayDate, 3) < 5) {
1075 4
                        $holidayDates[] = $holidayDate;
1076
                    }
1077
                }
1078
            }
1079 4
            if ($decrementing) {
1080 1
                rsort($holidayDates, SORT_NUMERIC);
1081
            } else {
1082 3
                sort($holidayDates, SORT_NUMERIC);
1083
            }
1084 4
            foreach ($holidayDates as $holidayDate) {
1085 4
                if ($decrementing) {
1086 1
                    if (($holidayDate <= $startDate) && ($holidayDate >= $endDate)) {
1087 1
                        if (!in_array($holidayDate, $holidayCountedArray)) {
1088 1
                            --$endDate;
1089 1
                            $holidayCountedArray[] = $holidayDate;
1090
                        }
1091
                    }
1092
                } else {
1093 3
                    if (($holidayDate >= $startDate) && ($holidayDate <= $endDate)) {
1094 3
                        if (!in_array($holidayDate, $holidayCountedArray)) {
1095 3
                            ++$endDate;
1096 3
                            $holidayCountedArray[] = $holidayDate;
1097
                        }
1098
                    }
1099
                }
1100
                //    Adjust the calculated end date if it falls over a weekend
1101 4
                $endDoW = self::WEEKDAY($endDate, 3);
1102 4
                if ($endDoW >= 5) {
1103 4
                    $endDate += ($decrementing) ? -$endDoW + 4 : 7 - $endDoW;
1104
                }
1105
            }
1106
        }
1107
1108 12
        switch (Functions::getReturnDateType()) {
1109
            case Functions::RETURNDATE_EXCEL:
1110 12
                return (float) $endDate;
1111
            case Functions::RETURNDATE_PHP_NUMERIC:
1112
                return (int) Date::excelToTimestamp($endDate);
1113
            case Functions::RETURNDATE_PHP_OBJECT:
1114
                return Date::excelToDateTimeObject($endDate);
1115
        }
1116
    }
1117
1118
    /**
1119
     * DAYOFMONTH.
1120
     *
1121
     * Returns the day of the month, for a specified date. The day is given as an integer
1122
     * ranging from 1 to 31.
1123
     *
1124
     * Excel Function:
1125
     *        DAY(dateValue)
1126
     *
1127
     * @param mixed $dateValue Excel date serial value (float), PHP date timestamp (integer),
1128
     *                                    PHP DateTime object, or a standard date string
1129
     *
1130
     * @return int|string Day of the month
1131
     */
1132 21
    public static function DAYOFMONTH($dateValue = 1)
1133
    {
1134 21
        $dateValue = Functions::flattenSingleValue($dateValue);
1135
1136 21
        if ($dateValue === null) {
1137
            $dateValue = 1;
1138 21
        } elseif (is_string($dateValue = self::getDateValue($dateValue))) {
1139 1
            return Functions::VALUE();
1140
        }
1141
1142 20
        if (Functions::getCompatibilityMode() == Functions::COMPATIBILITY_EXCEL) {
1143 20
            if ($dateValue < 0.0) {
1144 1
                return Functions::NAN();
1145 19
            } elseif ($dateValue < 1.0) {
1146 2
                return 0;
1147
            }
1148
        }
1149
1150
        // Execute function
1151 20
        $PHPDateObject = Date::excelToDateTimeObject($dateValue);
1152
1153 20
        return (int) $PHPDateObject->format('j');
1154
    }
1155
1156
    /**
1157
     * WEEKDAY.
1158
     *
1159
     * Returns the day of the week for a specified date. The day is given as an integer
1160
     * ranging from 0 to 7 (dependent on the requested style).
1161
     *
1162
     * Excel Function:
1163
     *        WEEKDAY(dateValue[,style])
1164
     *
1165
     * @param int $dateValue Excel date serial value (float), PHP date timestamp (integer),
1166
     *                                    PHP DateTime object, or a standard date string
1167
     * @param int $style A number that determines the type of return value
1168
     *                                        1 or omitted    Numbers 1 (Sunday) through 7 (Saturday).
1169
     *                                        2                Numbers 1 (Monday) through 7 (Sunday).
1170
     *                                        3                Numbers 0 (Monday) through 6 (Sunday).
1171
     *
1172
     * @return int|string Day of the week value
1173
     */
1174 57
    public static function WEEKDAY($dateValue = 1, $style = 1)
1175
    {
1176 57
        $dateValue = Functions::flattenSingleValue($dateValue);
1177 57
        $style = Functions::flattenSingleValue($style);
1178
1179 57
        if (!is_numeric($style)) {
1180 1
            return Functions::VALUE();
1181 56
        } elseif (($style < 1) || ($style > 3)) {
1182 1
            return Functions::NAN();
1183
        }
1184 55
        $style = floor($style);
1185
1186 55
        if ($dateValue === null) {
1187
            $dateValue = 1;
1188 55
        } elseif (is_string($dateValue = self::getDateValue($dateValue))) {
1189 1
            return Functions::VALUE();
1190 54
        } elseif ($dateValue < 0.0) {
1191 1
            return Functions::NAN();
1192
        }
1193
1194
        // Execute function
1195 53
        $PHPDateObject = Date::excelToDateTimeObject($dateValue);
1196 53
        $DoW = $PHPDateObject->format('w');
1197
1198 53
        $firstDay = 1;
1199
        switch ($style) {
1200 53
            case 1:
1201 8
                ++$DoW;
1202
1203 8
                break;
1204 45
            case 2:
1205 26
                if ($DoW == 0) {
1206 3
                    $DoW = 7;
1207
                }
1208
1209 26
                break;
1210 19
            case 3:
1211 19
                if ($DoW == 0) {
1212 3
                    $DoW = 7;
1213
                }
1214 19
                $firstDay = 0;
1215 19
                --$DoW;
1216
1217 19
                break;
1218
        }
1219 53
        if (Functions::getCompatibilityMode() == Functions::COMPATIBILITY_EXCEL) {
1220
            //    Test for Excel's 1900 leap year, and introduce the error as required
1221 53
            if (($PHPDateObject->format('Y') == 1900) && ($PHPDateObject->format('n') <= 2)) {
1222 2
                --$DoW;
1223 2
                if ($DoW < $firstDay) {
1224 1
                    $DoW += 7;
1225
                }
1226
            }
1227
        }
1228
1229 53
        return (int) $DoW;
1230
    }
1231
1232
    /**
1233
     * WEEKNUM.
1234
     *
1235
     * Returns the week of the year for a specified date.
1236
     * The WEEKNUM function considers the week containing January 1 to be the first week of the year.
1237
     * However, there is a European standard that defines the first week as the one with the majority
1238
     * of days (four or more) falling in the new year. This means that for years in which there are
1239
     * three days or less in the first week of January, the WEEKNUM function returns week numbers
1240
     * that are incorrect according to the European standard.
1241
     *
1242
     * Excel Function:
1243
     *        WEEKNUM(dateValue[,style])
1244
     *
1245
     * @param mixed $dateValue Excel date serial value (float), PHP date timestamp (integer),
1246
     *                                    PHP DateTime object, or a standard date string
1247
     * @param int $method Week begins on Sunday or Monday
1248
     *                                        1 or omitted    Week begins on Sunday.
1249
     *                                        2                Week begins on Monday.
1250
     *
1251
     * @return int|string Week Number
1252
     */
1253 15
    public static function WEEKNUM($dateValue = 1, $method = 1)
1254
    {
1255 15
        $dateValue = Functions::flattenSingleValue($dateValue);
1256 15
        $method = Functions::flattenSingleValue($method);
1257
1258 15
        if (!is_numeric($method)) {
1259 1
            return Functions::VALUE();
1260 14
        } elseif (($method < 1) || ($method > 2)) {
1261 1
            return Functions::NAN();
1262
        }
1263 13
        $method = floor($method);
1264
1265 13
        if ($dateValue === null) {
1266
            $dateValue = 1;
1267 13
        } elseif (is_string($dateValue = self::getDateValue($dateValue))) {
1268 1
            return Functions::VALUE();
1269 12
        } elseif ($dateValue < 0.0) {
1270 1
            return Functions::NAN();
1271
        }
1272
1273
        // Execute function
1274 11
        $PHPDateObject = Date::excelToDateTimeObject($dateValue);
1275 11
        $dayOfYear = $PHPDateObject->format('z');
1276 11
        $PHPDateObject->modify('-' . $dayOfYear . ' days');
1277 11
        $firstDayOfFirstWeek = $PHPDateObject->format('w');
1278 11
        $daysInFirstWeek = (6 - $firstDayOfFirstWeek + $method) % 7;
1279 11
        $interval = $dayOfYear - $daysInFirstWeek;
1280 11
        $weekOfYear = floor($interval / 7) + 1;
1281
1282 11
        if ($daysInFirstWeek) {
1283 8
            ++$weekOfYear;
1284
        }
1285
1286 11
        return (int) $weekOfYear;
1287
    }
1288
1289
    /**
1290
     * ISOWEEKNUM.
1291
     *
1292
     * Returns the ISO 8601 week number of the year for a specified date.
1293
     *
1294
     * Excel Function:
1295
     *        ISOWEEKNUM(dateValue)
1296
     *
1297
     * @param mixed $dateValue Excel date serial value (float), PHP date timestamp (integer),
1298
     *                                    PHP DateTime object, or a standard date string
1299
     *
1300
     * @return int|string Week Number
1301
     */
1302 8
    public static function ISOWEEKNUM($dateValue = 1)
1303
    {
1304 8
        $dateValue = Functions::flattenSingleValue($dateValue);
1305
1306 8
        if ($dateValue === null) {
1307
            $dateValue = 1;
1308 8
        } elseif (is_string($dateValue = self::getDateValue($dateValue))) {
1309 1
            return Functions::VALUE();
1310 7
        } elseif ($dateValue < 0.0) {
1311
            return Functions::NAN();
1312
        }
1313
1314
        // Execute function
1315 7
        $PHPDateObject = Date::excelToDateTimeObject($dateValue);
1316
1317 7
        return (int) $PHPDateObject->format('W');
1318
    }
1319
1320
    /**
1321
     * MONTHOFYEAR.
1322
     *
1323
     * Returns the month of a date represented by a serial number.
1324
     * The month is given as an integer, ranging from 1 (January) to 12 (December).
1325
     *
1326
     * Excel Function:
1327
     *        MONTH(dateValue)
1328
     *
1329
     * @param mixed $dateValue Excel date serial value (float), PHP date timestamp (integer),
1330
     *                                    PHP DateTime object, or a standard date string
1331
     *
1332
     * @return int|string Month of the year
1333
     */
1334 22
    public static function MONTHOFYEAR($dateValue = 1)
1335
    {
1336 22
        $dateValue = Functions::flattenSingleValue($dateValue);
1337
1338 22
        if (empty($dateValue)) {
1339 2
            $dateValue = 1;
1340
        }
1341 22
        if (is_string($dateValue = self::getDateValue($dateValue))) {
1342 1
            return Functions::VALUE();
1343 21
        } elseif ($dateValue < 0.0) {
1344 1
            return Functions::NAN();
1345
        }
1346
1347
        // Execute function
1348 20
        $PHPDateObject = Date::excelToDateTimeObject($dateValue);
1349
1350 20
        return (int) $PHPDateObject->format('n');
1351
    }
1352
1353
    /**
1354
     * YEAR.
1355
     *
1356
     * Returns the year corresponding to a date.
1357
     * The year is returned as an integer in the range 1900-9999.
1358
     *
1359
     * Excel Function:
1360
     *        YEAR(dateValue)
1361
     *
1362
     * @param mixed $dateValue Excel date serial value (float), PHP date timestamp (integer),
1363
     *                                    PHP DateTime object, or a standard date string
1364
     *
1365
     * @return int|string Year
1366
     */
1367 36
    public static function YEAR($dateValue = 1)
1368
    {
1369 36
        $dateValue = Functions::flattenSingleValue($dateValue);
1370
1371 36
        if ($dateValue === null) {
1372 1
            $dateValue = 1;
1373 35
        } elseif (is_string($dateValue = self::getDateValue($dateValue))) {
1374 1
            return Functions::VALUE();
1375 34
        } elseif ($dateValue < 0.0) {
1376 1
            return Functions::NAN();
1377
        }
1378
1379
        // Execute function
1380 34
        $PHPDateObject = Date::excelToDateTimeObject($dateValue);
1381
1382 34
        return (int) $PHPDateObject->format('Y');
1383
    }
1384
1385
    /**
1386
     * HOUROFDAY.
1387
     *
1388
     * Returns the hour of a time value.
1389
     * The hour is given as an integer, ranging from 0 (12:00 A.M.) to 23 (11:00 P.M.).
1390
     *
1391
     * Excel Function:
1392
     *        HOUR(timeValue)
1393
     *
1394
     * @param mixed $timeValue Excel date serial value (float), PHP date timestamp (integer),
1395
     *                                    PHP DateTime object, or a standard time string
1396
     *
1397
     * @return int|string Hour
1398
     */
1399 12
    public static function HOUROFDAY($timeValue = 0)
1400
    {
1401 12
        $timeValue = Functions::flattenSingleValue($timeValue);
1402
1403 12
        if (!is_numeric($timeValue)) {
1404 4
            if (Functions::getCompatibilityMode() == Functions::COMPATIBILITY_GNUMERIC) {
1405
                $testVal = strtok($timeValue, '/-: ');
1406
                if (strlen($testVal) < strlen($timeValue)) {
1407
                    return Functions::VALUE();
1408
                }
1409
            }
1410 4
            $timeValue = self::getTimeValue($timeValue);
1411 4
            if (is_string($timeValue)) {
1412 1
                return Functions::VALUE();
1413
            }
1414
        }
1415
        // Execute function
1416 11
        if ($timeValue >= 1) {
1417 3
            $timeValue = fmod($timeValue, 1);
1418 8
        } elseif ($timeValue < 0.0) {
1419 1
            return Functions::NAN();
1420
        }
1421 10
        $timeValue = Date::excelToTimestamp($timeValue);
1422
1423 10
        return (int) gmdate('G', $timeValue);
1424
    }
1425
1426
    /**
1427
     * MINUTE.
1428
     *
1429
     * Returns the minutes of a time value.
1430
     * The minute is given as an integer, ranging from 0 to 59.
1431
     *
1432
     * Excel Function:
1433
     *        MINUTE(timeValue)
1434
     *
1435
     * @param mixed $timeValue Excel date serial value (float), PHP date timestamp (integer),
1436
     *                                    PHP DateTime object, or a standard time string
1437
     *
1438
     * @return int|string Minute
1439
     */
1440 12
    public static function MINUTE($timeValue = 0)
1441
    {
1442 12
        $timeValue = $timeTester = Functions::flattenSingleValue($timeValue);
0 ignored issues
show
Unused Code introduced by
The assignment to $timeTester is dead and can be removed.
Loading history...
1443
1444 12
        if (!is_numeric($timeValue)) {
1445 4
            if (Functions::getCompatibilityMode() == Functions::COMPATIBILITY_GNUMERIC) {
1446
                $testVal = strtok($timeValue, '/-: ');
1447
                if (strlen($testVal) < strlen($timeValue)) {
1448
                    return Functions::VALUE();
1449
                }
1450
            }
1451 4
            $timeValue = self::getTimeValue($timeValue);
1452 4
            if (is_string($timeValue)) {
1453 1
                return Functions::VALUE();
1454
            }
1455
        }
1456
        // Execute function
1457 11
        if ($timeValue >= 1) {
1458 3
            $timeValue = fmod($timeValue, 1);
1459 8
        } elseif ($timeValue < 0.0) {
1460 1
            return Functions::NAN();
1461
        }
1462 10
        $timeValue = Date::excelToTimestamp($timeValue);
1463
1464 10
        return (int) gmdate('i', $timeValue);
1465
    }
1466
1467
    /**
1468
     * SECOND.
1469
     *
1470
     * Returns the seconds of a time value.
1471
     * The second is given as an integer in the range 0 (zero) to 59.
1472
     *
1473
     * Excel Function:
1474
     *        SECOND(timeValue)
1475
     *
1476
     * @param mixed $timeValue Excel date serial value (float), PHP date timestamp (integer),
1477
     *                                    PHP DateTime object, or a standard time string
1478
     *
1479
     * @return int|string Second
1480
     */
1481 12
    public static function SECOND($timeValue = 0)
1482
    {
1483 12
        $timeValue = Functions::flattenSingleValue($timeValue);
1484
1485 12
        if (!is_numeric($timeValue)) {
1486 4
            if (Functions::getCompatibilityMode() == Functions::COMPATIBILITY_GNUMERIC) {
1487
                $testVal = strtok($timeValue, '/-: ');
1488
                if (strlen($testVal) < strlen($timeValue)) {
1489
                    return Functions::VALUE();
1490
                }
1491
            }
1492 4
            $timeValue = self::getTimeValue($timeValue);
1493 4
            if (is_string($timeValue)) {
1494 1
                return Functions::VALUE();
1495
            }
1496
        }
1497
        // Execute function
1498 11
        if ($timeValue >= 1) {
1499 3
            $timeValue = fmod($timeValue, 1);
1500 8
        } elseif ($timeValue < 0.0) {
1501 1
            return Functions::NAN();
1502
        }
1503 10
        $timeValue = Date::excelToTimestamp($timeValue);
1504
1505 10
        return (int) gmdate('s', $timeValue);
1506
    }
1507
1508
    /**
1509
     * EDATE.
1510
     *
1511
     * Returns the serial number that represents the date that is the indicated number of months
1512
     * before or after a specified date (the start_date).
1513
     * Use EDATE to calculate maturity dates or due dates that fall on the same day of the month
1514
     * as the date of issue.
1515
     *
1516
     * Excel Function:
1517
     *        EDATE(dateValue,adjustmentMonths)
1518
     *
1519
     * @param mixed $dateValue Excel date serial value (float), PHP date timestamp (integer),
1520
     *                                        PHP DateTime object, or a standard date string
1521
     * @param int $adjustmentMonths The number of months before or after start_date.
1522
     *                                        A positive value for months yields a future date;
1523
     *                                        a negative value yields a past date.
1524
     *
1525
     * @return mixed Excel date/time serial value, PHP date/time serial value or PHP date/time object,
1526
     *                        depending on the value of the ReturnDateType flag
1527
     */
1528 17
    public static function EDATE($dateValue = 1, $adjustmentMonths = 0)
1529
    {
1530 17
        $dateValue = Functions::flattenSingleValue($dateValue);
1531 17
        $adjustmentMonths = Functions::flattenSingleValue($adjustmentMonths);
1532
1533 17
        if (!is_numeric($adjustmentMonths)) {
1534 1
            return Functions::VALUE();
1535
        }
1536 16
        $adjustmentMonths = floor($adjustmentMonths);
1537
1538 16
        if (is_string($dateValue = self::getDateValue($dateValue))) {
1539 1
            return Functions::VALUE();
1540
        }
1541
1542
        // Execute function
1543 15
        $PHPDateObject = self::adjustDateByMonths($dateValue, $adjustmentMonths);
1544
1545 15
        switch (Functions::getReturnDateType()) {
1546
            case Functions::RETURNDATE_EXCEL:
1547 13
                return (float) Date::PHPToExcel($PHPDateObject);
1548
            case Functions::RETURNDATE_PHP_NUMERIC:
1549 1
                return (int) Date::excelToTimestamp(Date::PHPToExcel($PHPDateObject));
1 ignored issue
show
Bug introduced by
It seems like PhpOffice\PhpSpreadsheet...ToExcel($PHPDateObject) can also be of type false; however, parameter $excelTimestamp of PhpOffice\PhpSpreadsheet...ate::excelToTimestamp() does only seem to accept integer|double, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

1549
                return (int) Date::excelToTimestamp(/** @scrutinizer ignore-type */ Date::PHPToExcel($PHPDateObject));
Loading history...
1550
            case Functions::RETURNDATE_PHP_OBJECT:
1551 1
                return $PHPDateObject;
1552
        }
1553
    }
1554
1555
    /**
1556
     * EOMONTH.
1557
     *
1558
     * Returns the date value for the last day of the month that is the indicated number of months
1559
     * before or after start_date.
1560
     * Use EOMONTH to calculate maturity dates or due dates that fall on the last day of the month.
1561
     *
1562
     * Excel Function:
1563
     *        EOMONTH(dateValue,adjustmentMonths)
1564
     *
1565
     * @param mixed $dateValue Excel date serial value (float), PHP date timestamp (integer),
1566
     *                                        PHP DateTime object, or a standard date string
1567
     * @param int $adjustmentMonths The number of months before or after start_date.
1568
     *                                        A positive value for months yields a future date;
1569
     *                                        a negative value yields a past date.
1570
     *
1571
     * @return mixed Excel date/time serial value, PHP date/time serial value or PHP date/time object,
1572
     *                        depending on the value of the ReturnDateType flag
1573
     */
1574 19
    public static function EOMONTH($dateValue = 1, $adjustmentMonths = 0)
1575
    {
1576 19
        $dateValue = Functions::flattenSingleValue($dateValue);
1577 19
        $adjustmentMonths = Functions::flattenSingleValue($adjustmentMonths);
1578
1579 19
        if (!is_numeric($adjustmentMonths)) {
1580 1
            return Functions::VALUE();
1581
        }
1582 18
        $adjustmentMonths = floor($adjustmentMonths);
1583
1584 18
        if (is_string($dateValue = self::getDateValue($dateValue))) {
1585 1
            return Functions::VALUE();
1586
        }
1587
1588
        // Execute function
1589 17
        $PHPDateObject = self::adjustDateByMonths($dateValue, $adjustmentMonths + 1);
1590 17
        $adjustDays = (int) $PHPDateObject->format('d');
1591 17
        $adjustDaysString = '-' . $adjustDays . ' days';
1592 17
        $PHPDateObject->modify($adjustDaysString);
1593
1594 17
        switch (Functions::getReturnDateType()) {
1595
            case Functions::RETURNDATE_EXCEL:
1596 15
                return (float) Date::PHPToExcel($PHPDateObject);
1597
            case Functions::RETURNDATE_PHP_NUMERIC:
1598 1
                return (int) Date::excelToTimestamp(Date::PHPToExcel($PHPDateObject));
1 ignored issue
show
Bug introduced by
It seems like PhpOffice\PhpSpreadsheet...ToExcel($PHPDateObject) can also be of type false; however, parameter $excelTimestamp of PhpOffice\PhpSpreadsheet...ate::excelToTimestamp() does only seem to accept integer|double, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

1598
                return (int) Date::excelToTimestamp(/** @scrutinizer ignore-type */ Date::PHPToExcel($PHPDateObject));
Loading history...
1599
            case Functions::RETURNDATE_PHP_OBJECT:
1600 1
                return $PHPDateObject;
1601
        }
1602
    }
1603
}
1604