Completed
Push — develop ( 962915...ae1b85 )
by Adrien
27:38
created

DateTime::SECOND()   C

Complexity

Conditions 7
Paths 12

Size

Total Lines 26
Code Lines 16

Duplication

Lines 26
Ratio 100 %

Code Coverage

Tests 13
CRAP Score 7.3229

Importance

Changes 0
Metric Value
cc 7
eloc 16
nc 12
nop 1
dl 26
loc 26
ccs 13
cts 16
cp 0.8125
crap 7.3229
rs 6.7272
c 0
b 0
f 0
1
<?php
2
3
namespace PhpOffice\PhpSpreadsheet\Calculation;
4
5
/**
6
 * Copyright (c) 2006 - 2016 PhpSpreadsheet
7
 *
8
 * This library is free software; you can redistribute it and/or
9
 * modify it under the terms of the GNU Lesser General Public
10
 * License as published by the Free Software Foundation; either
11
 * version 2.1 of the License, or (at your option) any later version.
12
 *
13
 * This library is distributed in the hope that it will be useful,
14
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16
 * Lesser General Public License for more details.
17
 *
18
 * You should have received a copy of the GNU Lesser General Public
19
 * License along with this library; if not, write to the Free Software
20
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21
 *
22
 * @category    PhpSpreadsheet
23
 * @copyright    Copyright (c) 2006 - 2016 PhpSpreadsheet (https://github.com/PHPOffice/PhpSpreadsheet)
24
 * @license        http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt    LGPL
25
 * @version        ##VERSION##, ##DATE##
26
 */
27
class DateTime
28
{
29
    /**
30
     * Identify if a year is a leap year or not
31
     *
32
     * @param    int    $year    The year to test
33
     * @return    bool            TRUE if the year is a leap year, otherwise FALSE
34
     */
35 20
    public static function isLeapYear($year)
36
    {
37 20
        return (($year % 4) == 0) && (($year % 100) != 0) || (($year % 400) == 0);
38
    }
39
40
    /**
41
     * Return the number of days between two dates based on a 360 day calendar
42
     *
43
     * @param    int    $startDay        Day of month of the start date
44
     * @param    int    $startMonth        Month of the start date
45
     * @param    int    $startYear        Year of the start date
46
     * @param    int    $endDay            Day of month of the start date
47
     * @param    int    $endMonth        Month of the start date
48
     * @param    int    $endYear        Year of the start date
49
     * @param    bool $methodUS        Whether to use the US method or the European method of calculation
50
     * @return    int    Number of days between the start date and the end date
51
     */
52 68
    private static function dateDiff360($startDay, $startMonth, $startYear, $endDay, $endMonth, $endYear, $methodUS)
53
    {
54 68
        if ($startDay == 31) {
55 12
            --$startDay;
56 56
        } elseif ($methodUS && ($startMonth == 2 && ($startDay == 29 || ($startDay == 28 && !self::isLeapYear($startYear))))) {
57 1
            $startDay = 30;
58
        }
59 68
        if ($endDay == 31) {
60 20
            if ($methodUS && $startDay != 30) {
61 9
                $endDay = 1;
62 9
                if ($endMonth == 12) {
63 3
                    ++$endYear;
64 3
                    $endMonth = 1;
65
                } else {
66 9
                    ++$endMonth;
67
                }
68
            } else {
69 11
                $endDay = 30;
70
            }
71
        }
72
73 68
        return $endDay + $endMonth * 30 + $endYear * 360 - $startDay - $startMonth * 30 - $startYear * 360;
74
    }
75
76
    /**
77
     * getDateValue
78
     *
79
     * @param    string    $dateValue
80
     * @return    mixed    Excel date/time serial value, or string if error
81
     */
82 381
    public static function getDateValue($dateValue)
83
    {
84 381
        if (!is_numeric($dateValue)) {
85 348
            if ((is_string($dateValue)) &&
86 348
                (Functions::getCompatibilityMode() == Functions::COMPATIBILITY_GNUMERIC)) {
87
                return Functions::VALUE();
88
            }
89 348
            if ((is_object($dateValue)) && ($dateValue instanceof \DateTime)) {
90
                $dateValue = \PhpOffice\PhpSpreadsheet\Shared\Date::PHPToExcel($dateValue);
91
            } else {
92 348
                $saveReturnDateType = Functions::getReturnDateType();
93 348
                Functions::setReturnDateType(Functions::RETURNDATE_EXCEL);
94 348
                $dateValue = self::DATEVALUE($dateValue);
95 348
                Functions::setReturnDateType($saveReturnDateType);
96
            }
97
        }
98
99 381
        return $dateValue;
100
    }
101
102
    /**
103
     * getTimeValue
104
     *
105
     * @param    string    $timeValue
106
     * @return    mixed    Excel date/time serial value, or string if error
107
     */
108 12
    private static function getTimeValue($timeValue)
109
    {
110 12
        $saveReturnDateType = Functions::getReturnDateType();
111 12
        Functions::setReturnDateType(Functions::RETURNDATE_EXCEL);
112 12
        $timeValue = self::TIMEVALUE($timeValue);
113 12
        Functions::setReturnDateType($saveReturnDateType);
114
115 12
        return $timeValue;
116
    }
117
118 32
    private static function adjustDateByMonths($dateValue = 0, $adjustmentMonths = 0)
119
    {
120
        // Execute function
121 32
        $PHPDateObject = \PhpOffice\PhpSpreadsheet\Shared\Date::excelToDateTimeObject($dateValue);
122 32
        $oMonth = (int) $PHPDateObject->format('m');
123 32
        $oYear = (int) $PHPDateObject->format('Y');
124
125 32
        $adjustmentMonthsString = (string) $adjustmentMonths;
126 32
        if ($adjustmentMonths > 0) {
127 15
            $adjustmentMonthsString = '+' . $adjustmentMonths;
128
        }
129 32
        if ($adjustmentMonths != 0) {
130 26
            $PHPDateObject->modify($adjustmentMonthsString . ' months');
131
        }
132 32
        $nMonth = (int) $PHPDateObject->format('m');
133 32
        $nYear = (int) $PHPDateObject->format('Y');
134
135 32
        $monthDiff = ($nMonth - $oMonth) + (($nYear - $oYear) * 12);
136 32
        if ($monthDiff != $adjustmentMonths) {
137 5
            $adjustDays = (int) $PHPDateObject->format('d');
138 5
            $adjustDaysString = '-' . $adjustDays . ' days';
139 5
            $PHPDateObject->modify($adjustDaysString);
140
        }
141
142 32
        return $PHPDateObject;
143
    }
144
145
    /**
146
     * DATETIMENOW
147
     *
148
     * Returns the current date and time.
149
     * The NOW function is useful when you need to display the current date and time on a worksheet or
150
     * calculate a value based on the current date and time, and have that value updated each time you
151
     * open the worksheet.
152
     *
153
     * NOTE: When used in a Cell Formula, MS Excel changes the cell format so that it matches the date
154
     * and time format of your regional settings. PhpSpreadsheet does not change cell formatting in this way.
155
     *
156
     * Excel Function:
157
     *        NOW()
158
     *
159
     * @category Date/Time Functions
160
     * @return    mixed    Excel date/time serial value, PHP date/time serial value or PHP date/time object,
161
     *                        depending on the value of the ReturnDateType flag
162
     */
163
    public static function DATETIMENOW()
164
    {
165
        $saveTimeZone = date_default_timezone_get();
166
        date_default_timezone_set('UTC');
167
        $retValue = false;
168
        switch (Functions::getReturnDateType()) {
169
            case Functions::RETURNDATE_EXCEL:
170
                $retValue = (float) \PhpOffice\PhpSpreadsheet\Shared\Date::PHPToExcel(time());
171
                break;
172
            case Functions::RETURNDATE_PHP_NUMERIC:
173
                $retValue = (integer) time();
174
                break;
175
            case Functions::RETURNDATE_PHP_OBJECT:
176
                $retValue = new \DateTime();
177
                break;
178
        }
179
        date_default_timezone_set($saveTimeZone);
180
181
        return $retValue;
182
    }
183
184
    /**
185
     * DATENOW
186
     *
187
     * Returns the current date.
188
     * The NOW function is useful when you need to display the current date and time on a worksheet or
189
     * calculate a value based on the current date and time, and have that value updated each time you
190
     * open the worksheet.
191
     *
192
     * NOTE: When used in a Cell Formula, MS Excel changes the cell format so that it matches the date
193
     * and time format of your regional settings. PhpSpreadsheet does not change cell formatting in this way.
194
     *
195
     * Excel Function:
196
     *        TODAY()
197
     *
198
     * @category Date/Time Functions
199
     * @return    mixed    Excel date/time serial value, PHP date/time serial value or PHP date/time object,
200
     *                        depending on the value of the ReturnDateType flag
201
     */
202 1
    public static function DATENOW()
203
    {
204 1
        $saveTimeZone = date_default_timezone_get();
205 1
        date_default_timezone_set('UTC');
206 1
        $retValue = false;
207 1
        $excelDateTime = floor(\PhpOffice\PhpSpreadsheet\Shared\Date::PHPToExcel(time()));
208 1
        switch (Functions::getReturnDateType()) {
209 1
            case Functions::RETURNDATE_EXCEL:
210
                $retValue = (float) $excelDateTime;
211
                break;
212 1
            case Functions::RETURNDATE_PHP_NUMERIC:
213 1
                $retValue = (integer) \PhpOffice\PhpSpreadsheet\Shared\Date::excelToTimestamp($excelDateTime);
214 1
                break;
215
            case Functions::RETURNDATE_PHP_OBJECT:
216
                $retValue = \PhpOffice\PhpSpreadsheet\Shared\Date::excelToDateTimeObject($excelDateTime);
217
                break;
218
        }
219 1
        date_default_timezone_set($saveTimeZone);
220
221 1
        return $retValue;
222
    }
223
224
    /**
225
     * DATE
226
     *
227
     * The DATE function returns a value that represents a particular date.
228
     *
229
     * NOTE: When used in a Cell Formula, MS Excel changes the cell format so that it matches the date
230
     * format of your regional settings. PhpSpreadsheet does not change cell formatting in this way.
231
     *
232
     * Excel Function:
233
     *        DATE(year,month,day)
234
     *
235
     * PhpSpreadsheet is a lot more forgiving than MS Excel when passing non numeric values to this function.
236
     * A Month name or abbreviation (English only at this point) such as 'January' or 'Jan' will still be accepted,
237
     *     as will a day value with a suffix (e.g. '21st' rather than simply 21); again only English language.
238
     *
239
     * @category Date/Time Functions
240
     * @param    int        $year    The value of the year argument can include one to four digits.
241
     *                                Excel interprets the year argument according to the configured
242
     *                                date system: 1900 or 1904.
243
     *                                If year is between 0 (zero) and 1899 (inclusive), Excel adds that
244
     *                                value to 1900 to calculate the year. For example, DATE(108,1,2)
245
     *                                returns January 2, 2008 (1900+108).
246
     *                                If year is between 1900 and 9999 (inclusive), Excel uses that
247
     *                                value as the year. For example, DATE(2008,1,2) returns January 2,
248
     *                                2008.
249
     *                                If year is less than 0 or is 10000 or greater, Excel returns the
250
     *                                #NUM! error value.
251
     * @param    int        $month    A positive or negative integer representing the month of the year
252
     *                                from 1 to 12 (January to December).
253
     *                                If month is greater than 12, month adds that number of months to
254
     *                                the first month in the year specified. For example, DATE(2008,14,2)
255
     *                                returns the serial number representing February 2, 2009.
256
     *                                If month is less than 1, month subtracts the magnitude of that
257
     *                                number of months, plus 1, from the first month in the year
258
     *                                specified. For example, DATE(2008,-3,2) returns the serial number
259
     *                                representing September 2, 2007.
260
     * @param    int        $day    A positive or negative integer representing the day of the month
261
     *                                from 1 to 31.
262
     *                                If day is greater than the number of days in the month specified,
263
     *                                day adds that number of days to the first day in the month. For
264
     *                                example, DATE(2008,1,35) returns the serial number representing
265
     *                                February 4, 2008.
266
     *                                If day is less than 1, day subtracts the magnitude that number of
267
     *                                days, plus one, from the first day of the month specified. For
268
     *                                example, DATE(2008,1,-15) returns the serial number representing
269
     *                                December 16, 2007.
270
     * @return    mixed    Excel date/time serial value, PHP date/time serial value or PHP date/time object,
271
     *                        depending on the value of the ReturnDateType flag
272
     */
273 83
    public static function DATE($year = 0, $month = 1, $day = 1)
274
    {
275 83
        $year = Functions::flattenSingleValue($year);
276 83
        $month = Functions::flattenSingleValue($month);
277 83
        $day = Functions::flattenSingleValue($day);
278
279 83
        if (($month !== null) && (!is_numeric($month))) {
280 3
            $month = \PhpOffice\PhpSpreadsheet\Shared\Date::monthStringToNumber($month);
0 ignored issues
show
Bug introduced by
It seems like $month defined by \PhpOffice\PhpSpreadshee...hStringToNumber($month) on line 280 can also be of type boolean or object; however, PhpOffice\PhpSpreadsheet...::monthStringToNumber() does only seem to accept string, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
281
        }
282
283 83
        if (($day !== null) && (!is_numeric($day))) {
284 3
            $day = \PhpOffice\PhpSpreadsheet\Shared\Date::dayStringToNumber($day);
0 ignored issues
show
Bug introduced by
It seems like $day defined by \PhpOffice\PhpSpreadshee...dayStringToNumber($day) on line 284 can also be of type boolean or object; however, PhpOffice\PhpSpreadsheet...te::dayStringToNumber() does only seem to accept string, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
285
        }
286
287 83
        $year = ($year !== null) ? \PhpOffice\PhpSpreadsheet\Shared\StringHelper::testStringAsNumeric($year) : 0;
288 83
        $month = ($month !== null) ? \PhpOffice\PhpSpreadsheet\Shared\StringHelper::testStringAsNumeric($month) : 0;
289 83
        $day = ($day !== null) ? \PhpOffice\PhpSpreadsheet\Shared\StringHelper::testStringAsNumeric($day) : 0;
290 83
        if ((!is_numeric($year)) ||
291 82
            (!is_numeric($month)) ||
292 83
            (!is_numeric($day))) {
293 3
            return Functions::VALUE();
294
        }
295 80
        $year = (integer) $year;
296 80
        $month = (integer) $month;
297 80
        $day = (integer) $day;
298
299 80
        $baseYear = \PhpOffice\PhpSpreadsheet\Shared\Date::getExcelCalendar();
300
        // Validate parameters
301 80
        if ($year < ($baseYear - 1900)) {
302 2
            return Functions::NAN();
303
        }
304 78
        if ((($baseYear - 1900) != 0) && ($year < $baseYear) && ($year >= 1900)) {
305 1
            return Functions::NAN();
306
        }
307
308 77
        if (($year < $baseYear) && ($year >= ($baseYear - 1900))) {
309 6
            $year += 1900;
310
        }
311
312 77
        if ($month < 1) {
313
            //    Handle year/month adjustment if month < 1
314 21
            --$month;
315 21
            $year += ceil($month / 12) - 1;
316 21
            $month = 13 - abs($month % 12);
317 56
        } elseif ($month > 12) {
318
            //    Handle year/month adjustment if month > 12
319 7
            $year += floor($month / 12);
320 7
            $month = ($month % 12);
321
        }
322
323
        // Re-validate the year parameter after adjustments
324 77
        if (($year < $baseYear) || ($year >= 10000)) {
325 2
            return Functions::NAN();
326
        }
327
328
        // Execute function
329 75
        $excelDateValue = \PhpOffice\PhpSpreadsheet\Shared\Date::formattedPHPToExcel($year, $month, $day);
330 75 View Code Duplication
        switch (Functions::getReturnDateType()) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
331 75
            case Functions::RETURNDATE_EXCEL:
332 73
                return (float) $excelDateValue;
333 2
            case Functions::RETURNDATE_PHP_NUMERIC:
334 1
                return (integer) \PhpOffice\PhpSpreadsheet\Shared\Date::excelToTimestamp($excelDateValue);
335 1
            case Functions::RETURNDATE_PHP_OBJECT:
336 1
                return \PhpOffice\PhpSpreadsheet\Shared\Date::excelToDateTimeObject($excelDateValue);
337
        }
338
    }
339
340
    /**
341
     * TIME
342
     *
343
     * The TIME function returns a value that represents a particular time.
344
     *
345
     * NOTE: When used in a Cell Formula, MS Excel changes the cell format so that it matches the time
346
     * format of your regional settings. PhpSpreadsheet does not change cell formatting in this way.
347
     *
348
     * Excel Function:
349
     *        TIME(hour,minute,second)
350
     *
351
     * @category Date/Time Functions
352
     * @param    int        $hour        A number from 0 (zero) to 32767 representing the hour.
353
     *                                    Any value greater than 23 will be divided by 24 and the remainder
354
     *                                    will be treated as the hour value. For example, TIME(27,0,0) =
355
     *                                    TIME(3,0,0) = .125 or 3:00 AM.
356
     * @param    int        $minute        A number from 0 to 32767 representing the minute.
357
     *                                    Any value greater than 59 will be converted to hours and minutes.
358
     *                                    For example, TIME(0,750,0) = TIME(12,30,0) = .520833 or 12:30 PM.
359
     * @param    int        $second        A number from 0 to 32767 representing the second.
360
     *                                    Any value greater than 59 will be converted to hours, minutes,
361
     *                                    and seconds. For example, TIME(0,0,2000) = TIME(0,33,22) = .023148
362
     *                                    or 12:33:20 AM
363
     * @return    mixed    Excel date/time serial value, PHP date/time serial value or PHP date/time object,
364
     *                        depending on the value of the ReturnDateType flag
365
     */
366 24
    public static function TIME($hour = 0, $minute = 0, $second = 0)
367
    {
368 24
        $hour = Functions::flattenSingleValue($hour);
369 24
        $minute = Functions::flattenSingleValue($minute);
370 24
        $second = Functions::flattenSingleValue($second);
371
372 24
        if ($hour == '') {
373
            $hour = 0;
374
        }
375 24
        if ($minute == '') {
376 5
            $minute = 0;
377
        }
378 24
        if ($second == '') {
379 5
            $second = 0;
380
        }
381
382 24
        if ((!is_numeric($hour)) || (!is_numeric($minute)) || (!is_numeric($second))) {
383 1
            return Functions::VALUE();
384
        }
385 23
        $hour = (integer) $hour;
386 23
        $minute = (integer) $minute;
387 23
        $second = (integer) $second;
388
389 23 View Code Duplication
        if ($second < 0) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
390 4
            $minute += floor($second / 60);
391 4
            $second = 60 - abs($second % 60);
392 4
            if ($second == 60) {
393 4
                $second = 0;
394
            }
395 19
        } elseif ($second >= 60) {
396 1
            $minute += floor($second / 60);
397 1
            $second = $second % 60;
398
        }
399 23 View Code Duplication
        if ($minute < 0) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
400 7
            $hour += floor($minute / 60);
401 7
            $minute = 60 - abs($minute % 60);
402 7
            if ($minute == 60) {
403 7
                $minute = 0;
404
            }
405 16
        } elseif ($minute >= 60) {
406 3
            $hour += floor($minute / 60);
407 3
            $minute = $minute % 60;
408
        }
409
410 23
        if ($hour > 23) {
411 1
            $hour = $hour % 24;
412 22
        } elseif ($hour < 0) {
413 2
            return Functions::NAN();
414
        }
415
416
        // Execute function
417 21
        switch (Functions::getReturnDateType()) {
418 21
            case Functions::RETURNDATE_EXCEL:
419 19
                $date = 0;
420 19
                $calendar = \PhpOffice\PhpSpreadsheet\Shared\Date::getExcelCalendar();
421 19
                if ($calendar != \PhpOffice\PhpSpreadsheet\Shared\Date::CALENDAR_WINDOWS_1900) {
422
                    $date = 1;
423
                }
424
425 19
                return (float) \PhpOffice\PhpSpreadsheet\Shared\Date::formattedPHPToExcel($calendar, 1, $date, $hour, $minute, $second);
426 2
            case Functions::RETURNDATE_PHP_NUMERIC:
427 1
                return (integer) \PhpOffice\PhpSpreadsheet\Shared\Date::excelToTimestamp(\PhpOffice\PhpSpreadsheet\Shared\Date::formattedPHPToExcel(1970, 1, 1, $hour, $minute, $second)); // -2147468400; //    -2147472000 + 3600
428 1
            case Functions::RETURNDATE_PHP_OBJECT:
429 1
                $dayAdjust = 0;
430 1 View Code Duplication
                if ($hour < 0) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
431
                    $dayAdjust = floor($hour / 24);
432
                    $hour = 24 - abs($hour % 24);
433
                    if ($hour == 24) {
434
                        $hour = 0;
435
                    }
436 1
                } elseif ($hour >= 24) {
437
                    $dayAdjust = floor($hour / 24);
438
                    $hour = $hour % 24;
439
                }
440 1
                $phpDateObject = new \DateTime('1900-01-01 ' . $hour . ':' . $minute . ':' . $second);
441 1
                if ($dayAdjust != 0) {
442
                    $phpDateObject->modify($dayAdjust . ' days');
443
                }
444
445 1
                return $phpDateObject;
446
        }
447
    }
448
449
    /**
450
     * DATEVALUE
451
     *
452
     * Returns a value that represents a particular date.
453
     * Use DATEVALUE to convert a date represented by a text string to an Excel or PHP date/time stamp
454
     * value.
455
     *
456
     * NOTE: When used in a Cell Formula, MS Excel changes the cell format so that it matches the date
457
     * format of your regional settings. PhpSpreadsheet does not change cell formatting in this way.
458
     *
459
     * Excel Function:
460
     *        DATEVALUE(dateValue)
461
     *
462
     * @category Date/Time Functions
463
     * @param    string    $dateValue        Text that represents a date in a Microsoft Excel date format.
464
     *                                    For example, "1/30/2008" or "30-Jan-2008" are text strings within
465
     *                                    quotation marks that represent dates. Using the default date
466
     *                                    system in Excel for Windows, date_text must represent a date from
467
     *                                    January 1, 1900, to December 31, 9999. Using the default date
468
     *                                    system in Excel for the Macintosh, date_text must represent a date
469
     *                                    from January 1, 1904, to December 31, 9999. DATEVALUE returns the
470
     *                                    #VALUE! error value if date_text is out of this range.
471
     * @return    mixed    Excel date/time serial value, PHP date/time serial value or PHP date/time object,
472
     *                        depending on the value of the ReturnDateType flag
473
     */
474 422
    public static function DATEVALUE($dateValue = 1)
475
    {
476 422
        $dateValueOrig = $dateValue;
0 ignored issues
show
Unused Code introduced by
$dateValueOrig is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
477 422
        $dateValue = trim(Functions::flattenSingleValue($dateValue), '"');
478
        //    Strip any ordinals because they're allowed in Excel (English only)
479 422
        $dateValue = preg_replace('/(\d)(st|nd|rd|th)([ -\/])/Ui', '$1$3', $dateValue);
480
        //    Convert separators (/ . or space) to hyphens (should also handle dot used for ordinals in some countries, e.g. Denmark, Germany)
481 422
        $dateValue = str_replace(['/', '.', '-', '  '], [' ', ' ', ' ', ' '], $dateValue);
482
483 422
        $yearFound = false;
484 422
        $t1 = explode(' ', $dateValue);
485 422
        foreach ($t1 as &$t) {
486 422
            if ((is_numeric($t)) && ($t > 31)) {
487 389
                if ($yearFound) {
488
                    return Functions::VALUE();
489
                } else {
490 389
                    if ($t < 100) {
491 2
                        $t += 1900;
492
                    }
493 422
                    $yearFound = true;
494
                }
495
            }
496
        }
497 422
        if ((count($t1) == 1) && (strpos($t, ':') != false)) {
0 ignored issues
show
Bug introduced by
The variable $t does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
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...
498
            //    We've been fed a time value without any date
499 1
            return 0.0;
500 421
        } elseif (count($t1) == 2) {
501
            //    We only have two parts of the date: either day/month or month/year
502 27
            if ($yearFound) {
503 3
                array_unshift($t1, 1);
504
            } else {
505 24
                if ($t1[1] > 29) {
506 1
                    $t1[1] += 1900;
507 1
                    array_unshift($t1, 1);
508
                } else {
509 23
                    array_push($t1, date('Y'));
510
                }
511
            }
512
        }
513 421
        unset($t);
514 421
        $dateValue = implode(' ', $t1);
515
516 421
        $PHPDateArray = date_parse($dateValue);
517 421
        if (($PHPDateArray === false) || ($PHPDateArray['error_count'] > 0)) {
518 315
            $testVal1 = strtok($dateValue, '- ');
519 315
            if ($testVal1 !== false) {
520 314
                $testVal2 = strtok('- ');
521 314
                if ($testVal2 !== false) {
522 300
                    $testVal3 = strtok('- ');
523 300
                    if ($testVal3 === false) {
524 300
                        $testVal3 = strftime('%Y');
525
                    }
526
                } else {
527 314
                    return Functions::VALUE();
528
                }
529
            } else {
530 1
                return Functions::VALUE();
531
            }
532 300
            if ($testVal1 < 31 && $testVal2 < 12 && $testVal3 < 12 && strlen($testVal3) == 2) {
533 1
                $testVal3 += 2000;
534
            }
535 300
            $PHPDateArray = date_parse($testVal1 . '-' . $testVal2 . '-' . $testVal3);
536 300
            if (($PHPDateArray === false) || ($PHPDateArray['error_count'] > 0)) {
537 25
                $PHPDateArray = date_parse($testVal2 . '-' . $testVal1 . '-' . $testVal3);
538 25
                if (($PHPDateArray === false) || ($PHPDateArray['error_count'] > 0)) {
539 22
                    return Functions::VALUE();
540
                }
541
            }
542
        }
543
544 390
        if (($PHPDateArray !== false) && ($PHPDateArray['error_count'] == 0)) {
545
            // Execute function
546 390
            if ($PHPDateArray['year'] == '') {
547
                $PHPDateArray['year'] = strftime('%Y');
548
            }
549 390
            if ($PHPDateArray['year'] < 1900) {
550 2
                return Functions::VALUE();
551
            }
552 388
            if ($PHPDateArray['month'] == '') {
553
                $PHPDateArray['month'] = strftime('%m');
554
            }
555 388
            if ($PHPDateArray['day'] == '') {
556
                $PHPDateArray['day'] = strftime('%d');
557
            }
558 388
            if (!checkdate($PHPDateArray['month'], $PHPDateArray['day'], $PHPDateArray['year'])) {
559 3
                return Functions::VALUE();
560
            }
561 385
            $excelDateValue = floor(
562 385
                \PhpOffice\PhpSpreadsheet\Shared\Date::formattedPHPToExcel(
563 385
                    $PHPDateArray['year'],
564 385
                    $PHPDateArray['month'],
565 385
                    $PHPDateArray['day'],
566 385
                    $PHPDateArray['hour'],
567 385
                    $PHPDateArray['minute'],
568 385
                    $PHPDateArray['second']
569
                )
570
            );
571 385 View Code Duplication
            switch (Functions::getReturnDateType()) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
572 385
                case Functions::RETURNDATE_EXCEL:
573 383
                    return (float) $excelDateValue;
574 2
                case Functions::RETURNDATE_PHP_NUMERIC:
575 1
                    return (integer) \PhpOffice\PhpSpreadsheet\Shared\Date::excelToTimestamp($excelDateValue);
576 1
                case Functions::RETURNDATE_PHP_OBJECT:
577 1
                    return new \DateTime($PHPDateArray['year'] . '-' . $PHPDateArray['month'] . '-' . $PHPDateArray['day'] . ' 00:00:00');
578
            }
579
        }
580
581
        return Functions::VALUE();
582
    }
583
584
    /**
585
     * TIMEVALUE
586
     *
587
     * Returns a value that represents a particular time.
588
     * Use TIMEVALUE to convert a time represented by a text string to an Excel or PHP date/time stamp
589
     * value.
590
     *
591
     * NOTE: When used in a Cell Formula, MS Excel changes the cell format so that it matches the time
592
     * format of your regional settings. PhpSpreadsheet does not change cell formatting in this way.
593
     *
594
     * Excel Function:
595
     *        TIMEVALUE(timeValue)
596
     *
597
     * @category Date/Time Functions
598
     * @param    string    $timeValue        A text string that represents a time in any one of the Microsoft
599
     *                                    Excel time formats; for example, "6:45 PM" and "18:45" text strings
600
     *                                    within quotation marks that represent time.
601
     *                                    Date information in time_text is ignored.
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 30
    public static function TIMEVALUE($timeValue)
606
    {
607 30
        $timeValue = trim(Functions::flattenSingleValue($timeValue), '"');
608 30
        $timeValue = str_replace(['/', '.'], ['-', '-'], $timeValue);
609
610 30
        $arraySplit = preg_split('/[\/:\-\s]/', $timeValue);
611 30
        if ((count($arraySplit) == 2 || count($arraySplit) == 3) && $arraySplit[0] > 24) {
612 1
            $arraySplit[0] = ($arraySplit[0] % 24);
613 1
            $timeValue = implode(':', $arraySplit);
614
        }
615
616 30
        $PHPDateArray = date_parse($timeValue);
617 30
        if (($PHPDateArray !== false) && ($PHPDateArray['error_count'] == 0)) {
618 25
            if (Functions::getCompatibilityMode() == Functions::COMPATIBILITY_OPENOFFICE) {
619
                $excelDateValue = \PhpOffice\PhpSpreadsheet\Shared\Date::formattedPHPToExcel(
620
                    $PHPDateArray['year'],
621
                    $PHPDateArray['month'],
622
                    $PHPDateArray['day'],
623
                    $PHPDateArray['hour'],
624
                    $PHPDateArray['minute'],
625
                    $PHPDateArray['second']
626
                );
627
            } else {
628 25
                $excelDateValue = \PhpOffice\PhpSpreadsheet\Shared\Date::formattedPHPToExcel(1900, 1, 1, $PHPDateArray['hour'], $PHPDateArray['minute'], $PHPDateArray['second']) - 1;
629
            }
630
631 25 View Code Duplication
            switch (Functions::getReturnDateType()) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
632 25
                case Functions::RETURNDATE_EXCEL:
633 23
                    return (float) $excelDateValue;
634 2
                case Functions::RETURNDATE_PHP_NUMERIC:
635 1
                    return (integer) $phpDateValue = \PhpOffice\PhpSpreadsheet\Shared\Date::excelToTimestamp($excelDateValue + 25569) - 3600;
636 1
                case Functions::RETURNDATE_PHP_OBJECT:
637 1
                    return new \DateTime('1900-01-01 ' . $PHPDateArray['hour'] . ':' . $PHPDateArray['minute'] . ':' . $PHPDateArray['second']);
638
            }
639
        }
640
641 5
        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
     * @return    int    Interval between the dates
653
     */
654 149
    public static function DATEDIF($startDate = 0, $endDate = 0, $unit = 'D')
655
    {
656 149
        $startDate = Functions::flattenSingleValue($startDate);
657 149
        $endDate = Functions::flattenSingleValue($endDate);
658 149
        $unit = strtoupper(Functions::flattenSingleValue($unit));
659
660 149
        if (is_string($startDate = self::getDateValue($startDate))) {
661 1
            return Functions::VALUE();
662
        }
663 148
        if (is_string($endDate = self::getDateValue($endDate))) {
664 1
            return Functions::VALUE();
665
        }
666
667
        // Validate parameters
668 147
        if ($startDate >= $endDate) {
669 1
            return Functions::NAN();
670
        }
671
672
        // Execute function
673 146
        $difference = $endDate - $startDate;
674
675 146
        $PHPStartDateObject = \PhpOffice\PhpSpreadsheet\Shared\Date::excelToDateTimeObject($startDate);
676 146
        $startDays = $PHPStartDateObject->format('j');
677 146
        $startMonths = $PHPStartDateObject->format('n');
678 146
        $startYears = $PHPStartDateObject->format('Y');
679
680 146
        $PHPEndDateObject = \PhpOffice\PhpSpreadsheet\Shared\Date::excelToDateTimeObject($endDate);
681 146
        $endDays = $PHPEndDateObject->format('j');
682 146
        $endMonths = $PHPEndDateObject->format('n');
683 146
        $endYears = $PHPEndDateObject->format('Y');
684
685 146
        $retVal = Functions::NAN();
0 ignored issues
show
Unused Code introduced by
$retVal is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
686
        switch ($unit) {
687 146
            case 'D':
688 63
                $retVal = intval($difference);
689 63
                break;
690 83 View Code Duplication
            case 'M':
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
691 15
                $retVal = intval($endMonths - $startMonths) + (intval($endYears - $startYears) * 12);
692
                //    We're only interested in full months
693 15
                if ($endDays < $startDays) {
694 3
                    --$retVal;
695
                }
696 15
                break;
697 68
            case 'Y':
698 17
                $retVal = intval($endYears - $startYears);
699
                //    We're only interested in full months
700 17
                if ($endMonths < $startMonths) {
701 5
                    --$retVal;
702 12
                } elseif (($endMonths == $startMonths) && ($endDays < $startDays)) {
703
                    // Remove start month
704 1
                    --$retVal;
705
                    // Remove end month
706 1
                    --$retVal;
707
                }
708 17
                break;
709 51
            case 'MD':
710 15
                if ($endDays < $startDays) {
711 3
                    $retVal = $endDays;
712 3
                    $PHPEndDateObject->modify('-' . $endDays . ' days');
713 3
                    $adjustDays = $PHPEndDateObject->format('j');
714 3
                    $retVal += ($adjustDays - $startDays);
715
                } else {
716 12
                    $retVal = $endDays - $startDays;
717
                }
718 15
                break;
719 36 View Code Duplication
            case 'YM':
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
720 15
                $retVal = intval($endMonths - $startMonths);
721 15
                if ($retVal < 0) {
722 4
                    $retVal += 12;
723
                }
724
                //    We're only interested in full months
725 15
                if ($endDays < $startDays) {
726 3
                    --$retVal;
727
                }
728 15
                break;
729 21
            case 'YD':
730 20
                $retVal = intval($difference);
731 20
                if ($endYears > $startYears) {
732 9
                    $isLeapStartYear = $PHPStartDateObject->format('L');
733 9
                    $wasLeapEndYear = $PHPEndDateObject->format('L');
734
735
                    // Adjust end year to be as close as possible as start year
736 9
                    while ($PHPEndDateObject >= $PHPStartDateObject) {
737 9
                        $PHPEndDateObject->modify('-1 year');
738 9
                        $endYears = $PHPEndDateObject->format('Y');
0 ignored issues
show
Unused Code introduced by
$endYears is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
739
                    }
740 9
                    $PHPEndDateObject->modify('+1 year');
741
742
                    // Get the result
743 9
                    $retVal = $PHPEndDateObject->diff($PHPStartDateObject)->days;
744
745
                    // Adjust for leap years cases
746 9
                    $isLeapEndYear = $PHPEndDateObject->format('L');
747 9
                    $limit = new \DateTime($PHPEndDateObject->format('Y-02-29'));
748 9
                    if (!$isLeapStartYear && !$wasLeapEndYear && $isLeapEndYear && $PHPEndDateObject >= $limit) {
749 1
                        --$retVal;
750
                    }
751
                }
752 20
                break;
753
            default:
754 1
                $retVal = Functions::VALUE();
755
        }
756
757 146
        return $retVal;
758
    }
759
760
    /**
761
     * DAYS360
762
     *
763
     * Returns the number of days between two dates based on a 360-day year (twelve 30-day months),
764
     * which is used in some accounting calculations. Use this function to help compute payments if
765
     * your accounting system is based on twelve 30-day months.
766
     *
767
     * Excel Function:
768
     *        DAYS360(startDate,endDate[,method])
769
     *
770
     * @category Date/Time Functions
771
     * @param    mixed        $startDate        Excel date serial value (float), PHP date timestamp (integer),
772
     *                                        PHP DateTime object, or a standard date string
773
     * @param    mixed        $endDate        Excel date serial value (float), PHP date timestamp (integer),
774
     *                                        PHP DateTime object, or a standard date string
775
     * @param    bool        $method            US or European Method
776
     *                                        FALSE or omitted: U.S. (NASD) method. If the starting date is
777
     *                                        the last day of a month, it becomes equal to the 30th of the
778
     *                                        same month. If the ending date is the last day of a month and
779
     *                                        the starting date is earlier than the 30th of a month, the
780
     *                                        ending date becomes equal to the 1st of the next month;
781
     *                                        otherwise the ending date becomes equal to the 30th of the
782
     *                                        same month.
783
     *                                        TRUE: European method. Starting dates and ending dates that
784
     *                                        occur on the 31st of a month become equal to the 30th of the
785
     *                                        same month.
786
     * @return    int        Number of days between start date and end date
787
     */
788 72
    public static function DAYS360($startDate = 0, $endDate = 0, $method = false)
789
    {
790 72
        $startDate = Functions::flattenSingleValue($startDate);
791 72
        $endDate = Functions::flattenSingleValue($endDate);
792
793 72
        if (is_string($startDate = self::getDateValue($startDate))) {
794 1
            return Functions::VALUE();
795
        }
796 71
        if (is_string($endDate = self::getDateValue($endDate))) {
797 1
            return Functions::VALUE();
798
        }
799
800 70
        if (!is_bool($method)) {
801 2
            return Functions::VALUE();
802
        }
803
804
        // Execute function
805 68
        $PHPStartDateObject = \PhpOffice\PhpSpreadsheet\Shared\Date::excelToDateTimeObject($startDate);
806 68
        $startDay = $PHPStartDateObject->format('j');
807 68
        $startMonth = $PHPStartDateObject->format('n');
808 68
        $startYear = $PHPStartDateObject->format('Y');
809
810 68
        $PHPEndDateObject = \PhpOffice\PhpSpreadsheet\Shared\Date::excelToDateTimeObject($endDate);
811 68
        $endDay = $PHPEndDateObject->format('j');
812 68
        $endMonth = $PHPEndDateObject->format('n');
813 68
        $endYear = $PHPEndDateObject->format('Y');
814
815 68
        return self::dateDiff360($startDay, $startMonth, $startYear, $endDay, $endMonth, $endYear, !$method);
816
    }
817
818
    /**
819
     * YEARFRAC
820
     *
821
     * Calculates the fraction of the year represented by the number of whole days between two dates
822
     * (the start_date and the end_date).
823
     * Use the YEARFRAC worksheet function to identify the proportion of a whole year's benefits or
824
     * obligations to assign to a specific term.
825
     *
826
     * Excel Function:
827
     *        YEARFRAC(startDate,endDate[,method])
828
     *
829
     * @category Date/Time Functions
830
     * @param    mixed    $startDate        Excel date serial value (float), PHP date timestamp (integer),
831
     *                                    PHP DateTime object, or a standard date string
832
     * @param    mixed    $endDate        Excel date serial value (float), PHP date timestamp (integer),
833
     *                                    PHP DateTime object, or a standard date string
834
     * @param    int    $method            Method used for the calculation
835
     *                                        0 or omitted    US (NASD) 30/360
836
     *                                        1                Actual/actual
837
     *                                        2                Actual/360
838
     *                                        3                Actual/365
839
     *                                        4                European 30/360
840
     * @return    float    fraction of the year
841
     */
842 89
    public static function YEARFRAC($startDate = 0, $endDate = 0, $method = 0)
843
    {
844 89
        $startDate = Functions::flattenSingleValue($startDate);
845 89
        $endDate = Functions::flattenSingleValue($endDate);
846 89
        $method = Functions::flattenSingleValue($method);
847
848 89
        if (is_string($startDate = self::getDateValue($startDate))) {
849 4
            return Functions::VALUE();
850
        }
851 85
        if (is_string($endDate = self::getDateValue($endDate))) {
852
            return Functions::VALUE();
853
        }
854
855 85
        if (((is_numeric($method)) && (!is_string($method))) || ($method == '')) {
856
            switch ($method) {
857 84
                case 0:
858 22
                    return self::DAYS360($startDate, $endDate) / 360;
859 62
                case 1:
860 19
                    $days = self::DATEDIF($startDate, $endDate);
861 19
                    $startYear = self::YEAR($startDate);
862 19
                    $endYear = self::YEAR($endDate);
863 19
                    $years = $endYear - $startYear + 1;
864 19
                    $leapDays = 0;
865 19
                    if ($years == 1) {
866 13
                        if (self::isLeapYear($endYear)) {
867 3
                            $startMonth = self::MONTHOFYEAR($startDate);
868 3
                            $endMonth = self::MONTHOFYEAR($endDate);
869 3
                            $endDay = self::DAYOFMONTH($endDate);
870 3
                            if (($startMonth < 3) ||
871 3
                                (($endMonth * 100 + $endDay) >= (2 * 100 + 29))) {
872 13
                                $leapDays += 1;
873
                            }
874
                        }
875
                    } else {
876 6
                        for ($year = $startYear; $year <= $endYear; ++$year) {
877 6
                            if ($year == $startYear) {
878 6
                                $startMonth = self::MONTHOFYEAR($startDate);
879 6
                                $startDay = self::DAYOFMONTH($startDate);
0 ignored issues
show
Unused Code introduced by
$startDay is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
880 6
                                if ($startMonth < 3) {
881 6
                                    $leapDays += (self::isLeapYear($year)) ? 1 : 0;
882
                                }
883 6
                            } elseif ($year == $endYear) {
884 6
                                $endMonth = self::MONTHOFYEAR($endDate);
885 6
                                $endDay = self::DAYOFMONTH($endDate);
886 6
                                if (($endMonth * 100 + $endDay) >= (2 * 100 + 29)) {
887 6
                                    $leapDays += (self::isLeapYear($year)) ? 1 : 0;
888
                                }
889
                            } else {
890 2
                                $leapDays += (self::isLeapYear($year)) ? 1 : 0;
891
                            }
892
                        }
893 6
                        if ($years == 2) {
894 4
                            if (($leapDays == 0) && (self::isLeapYear($startYear)) && ($days > 365)) {
895
                                $leapDays = 1;
896 4
                            } elseif ($days < 366) {
897 1
                                $years = 1;
898
                            }
899
                        }
900 6
                        $leapDays /= $years;
901
                    }
902
903 19
                    return $days / (365 + $leapDays);
904 43
                case 2:
905 14
                    return self::DATEDIF($startDate, $endDate) / 360;
906 29
                case 3:
907 14
                    return self::DATEDIF($startDate, $endDate) / 365;
908 15
                case 4:
909 15
                    return self::DAYS360($startDate, $endDate, true) / 360;
910
            }
911
        }
912
913 1
        return Functions::VALUE();
914
    }
915
916
    /**
917
     * NETWORKDAYS
918
     *
919
     * Returns the number of whole working days between start_date and end_date. Working days
920
     * exclude weekends and any dates identified in holidays.
921
     * Use NETWORKDAYS to calculate employee benefits that accrue based on the number of days
922
     * worked during a specific term.
923
     *
924
     * Excel Function:
925
     *        NETWORKDAYS(startDate,endDate[,holidays[,holiday[,...]]])
926
     *
927
     * @category Date/Time Functions
928
     * @param    mixed            $startDate        Excel date serial value (float), PHP date timestamp (integer),
929
     *                                            PHP DateTime object, or a standard date string
930
     * @param    mixed            $endDate        Excel date serial value (float), PHP date timestamp (integer),
931
     *                                            PHP DateTime object, or a standard date string
932
     * @return    int            Interval between the dates
933
     */
934 18
    public static function NETWORKDAYS($startDate, $endDate)
935
    {
936
        //    Retrieve the mandatory start and end date that are referenced in the function definition
937 18
        $startDate = Functions::flattenSingleValue($startDate);
938 18
        $endDate = Functions::flattenSingleValue($endDate);
939
        //    Flush the mandatory start and end date that are referenced in the function definition, and get the optional days
940 18
        $dateArgs = Functions::flattenArray(func_get_args());
941 18
        array_shift($dateArgs);
942 18
        array_shift($dateArgs);
943
944
        //    Validate the start and end dates
945 18
        if (is_string($startDate = $sDate = self::getDateValue($startDate))) {
946
            return Functions::VALUE();
947
        }
948 18
        $startDate = (float) floor($startDate);
949 18
        if (is_string($endDate = $eDate = self::getDateValue($endDate))) {
950
            return Functions::VALUE();
951
        }
952 18
        $endDate = (float) floor($endDate);
953
954 18
        if ($sDate > $eDate) {
955 2
            $startDate = $eDate;
956 2
            $endDate = $sDate;
957
        }
958
959
        // Execute function
960 18
        $startDoW = 6 - self::WEEKDAY($startDate, 2);
961 18
        if ($startDoW < 0) {
962
            $startDoW = 0;
963
        }
964 18
        $endDoW = self::WEEKDAY($endDate, 2);
965 18
        if ($endDoW >= 6) {
966 2
            $endDoW = 0;
967
        }
968
969 18
        $wholeWeekDays = floor(($endDate - $startDate) / 7) * 5;
970 18
        $partWeekDays = $endDoW + $startDoW;
971 18
        if ($partWeekDays > 5) {
972 14
            $partWeekDays -= 5;
973
        }
974
975
        //    Test any extra holiday parameters
976 18
        $holidayCountedArray = [];
977 18
        foreach ($dateArgs as $holidayDate) {
978 4
            if (is_string($holidayDate = self::getDateValue($holidayDate))) {
979
                return Functions::VALUE();
980
            }
981 4 View Code Duplication
            if (($holidayDate >= $startDate) && ($holidayDate <= $endDate)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
982 4
                if ((self::WEEKDAY($holidayDate, 2) < 6) && (!in_array($holidayDate, $holidayCountedArray))) {
983 4
                    --$partWeekDays;
984 4
                    $holidayCountedArray[] = $holidayDate;
985
                }
986
            }
987
        }
988
989 18
        if ($sDate > $eDate) {
990 2
            return 0 - ($wholeWeekDays + $partWeekDays);
991
        }
992
993 16
        return $wholeWeekDays + $partWeekDays;
994
    }
995
996
    /**
997
     * WORKDAY
998
     *
999
     * Returns the date that is the indicated number of working days before or after a date (the
1000
     * starting date). Working days exclude weekends and any dates identified as holidays.
1001
     * Use WORKDAY to exclude weekends or holidays when you calculate invoice due dates, expected
1002
     * delivery times, or the number of days of work performed.
1003
     *
1004
     * Excel Function:
1005
     *        WORKDAY(startDate,endDays[,holidays[,holiday[,...]]])
1006
     *
1007
     * @category Date/Time Functions
1008
     * @param    mixed        $startDate        Excel date serial value (float), PHP date timestamp (integer),
1009
     *                                        PHP DateTime object, or a standard date string
1010
     * @param    int        $endDays        The number of nonweekend and nonholiday days before or after
1011
     *                                        startDate. A positive value for days yields a future date; a
1012
     *                                        negative value yields a past date.
1013
     * @return    mixed    Excel date/time serial value, PHP date/time serial value or PHP date/time object,
1014
     *                        depending on the value of the ReturnDateType flag
1015
     */
1016 13
    public static function WORKDAY($startDate, $endDays)
1017
    {
1018
        //    Retrieve the mandatory start date and days that are referenced in the function definition
1019 13
        $startDate = Functions::flattenSingleValue($startDate);
1020 13
        $endDays = Functions::flattenSingleValue($endDays);
1021
        //    Flush the mandatory start date and days that are referenced in the function definition, and get the optional days
1022 13
        $dateArgs = Functions::flattenArray(func_get_args());
1023 13
        array_shift($dateArgs);
1024 13
        array_shift($dateArgs);
1025
1026 13
        if ((is_string($startDate = self::getDateValue($startDate))) || (!is_numeric($endDays))) {
1027 1
            return Functions::VALUE();
1028
        }
1029 12
        $startDate = (float) floor($startDate);
1030 12
        $endDays = (int) floor($endDays);
1031
        //    If endDays is 0, we always return startDate
1032 12
        if ($endDays == 0) {
1033
            return $startDate;
1034
        }
1035
1036 12
        $decrementing = ($endDays < 0) ? true : false;
1037
1038
        //    Adjust the start date if it falls over a weekend
1039
1040 12
        $startDoW = self::WEEKDAY($startDate, 3);
1041 12
        if (self::WEEKDAY($startDate, 3) >= 5) {
1042 4
            $startDate += ($decrementing) ? -$startDoW + 4 : 7 - $startDoW;
1043 4
            ($decrementing) ? $endDays++ : $endDays--;
1044
        }
1045
1046
        //    Add endDays
1047 12
        $endDate = (float) $startDate + (intval($endDays / 5) * 7) + ($endDays % 5);
1048
1049
        //    Adjust the calculated end date if it falls over a weekend
1050 12
        $endDoW = self::WEEKDAY($endDate, 3);
1051 12
        if ($endDoW >= 5) {
1052 1
            $endDate += ($decrementing) ? -$endDoW + 4 : 7 - $endDoW;
1053
        }
1054
1055
        //    Test any extra holiday parameters
1056 12
        if (!empty($dateArgs)) {
1057 4
            $holidayCountedArray = $holidayDates = [];
1058 4
            foreach ($dateArgs as $holidayDate) {
1059 4
                if (($holidayDate !== null) && (trim($holidayDate) > '')) {
1060 4
                    if (is_string($holidayDate = self::getDateValue($holidayDate))) {
1061
                        return Functions::VALUE();
1062
                    }
1063 4
                    if (self::WEEKDAY($holidayDate, 3) < 5) {
1064 4
                        $holidayDates[] = $holidayDate;
1065
                    }
1066
                }
1067
            }
1068 4
            if ($decrementing) {
1069 1
                rsort($holidayDates, SORT_NUMERIC);
1070
            } else {
1071 3
                sort($holidayDates, SORT_NUMERIC);
1072
            }
1073 4
            foreach ($holidayDates as $holidayDate) {
1074 4
                if ($decrementing) {
1075 1 View Code Duplication
                    if (($holidayDate <= $startDate) && ($holidayDate >= $endDate)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1076 1
                        if (!in_array($holidayDate, $holidayCountedArray)) {
1077 1
                            --$endDate;
1078 1
                            $holidayCountedArray[] = $holidayDate;
1079
                        }
1080
                    }
1081 View Code Duplication
                } else {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1082 3
                    if (($holidayDate >= $startDate) && ($holidayDate <= $endDate)) {
1083 3
                        if (!in_array($holidayDate, $holidayCountedArray)) {
1084 3
                            ++$endDate;
1085 3
                            $holidayCountedArray[] = $holidayDate;
1086
                        }
1087
                    }
1088
                }
1089
                //    Adjust the calculated end date if it falls over a weekend
1090 4
                $endDoW = self::WEEKDAY($endDate, 3);
1091 4
                if ($endDoW >= 5) {
1092 4
                    $endDate += ($decrementing) ? -$endDoW + 4 : 7 - $endDoW;
1093
                }
1094
            }
1095
        }
1096
1097 12 View Code Duplication
        switch (Functions::getReturnDateType()) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1098 12
            case Functions::RETURNDATE_EXCEL:
1099 12
                return (float) $endDate;
1100
            case Functions::RETURNDATE_PHP_NUMERIC:
1101
                return (integer) \PhpOffice\PhpSpreadsheet\Shared\Date::excelToTimestamp($endDate);
1102
            case Functions::RETURNDATE_PHP_OBJECT:
1103
                return \PhpOffice\PhpSpreadsheet\Shared\Date::excelToDateTimeObject($endDate);
1104
        }
1105
    }
1106
1107
    /**
1108
     * DAYOFMONTH
1109
     *
1110
     * Returns the day of the month, for a specified date. The day is given as an integer
1111
     * ranging from 1 to 31.
1112
     *
1113
     * Excel Function:
1114
     *        DAY(dateValue)
1115
     *
1116
     * @param    mixed    $dateValue        Excel date serial value (float), PHP date timestamp (integer),
1117
     *                                    PHP DateTime object, or a standard date string
1118
     * @return    int        Day of the month
1119
     */
1120 17
    public static function DAYOFMONTH($dateValue = 1)
1121
    {
1122 17
        $dateValue = Functions::flattenSingleValue($dateValue);
1123
1124 17
        if ($dateValue === null) {
1125
            $dateValue = 1;
1126 17
        } elseif (is_string($dateValue = self::getDateValue($dateValue))) {
1127 1
            return Functions::VALUE();
1128 16
        } elseif ($dateValue == 0.0) {
1129
            return 0;
1130 16
        } elseif ($dateValue < 0.0) {
1131 1
            return Functions::NAN();
1132
        }
1133
1134
        // Execute function
1135 15
        $PHPDateObject = \PhpOffice\PhpSpreadsheet\Shared\Date::excelToDateTimeObject($dateValue);
1136
1137 15
        return (int) $PHPDateObject->format('j');
1138
    }
1139
1140
    /**
1141
     * WEEKDAY
1142
     *
1143
     * Returns the day of the week for a specified date. The day is given as an integer
1144
     * ranging from 0 to 7 (dependent on the requested style).
1145
     *
1146
     * Excel Function:
1147
     *        WEEKDAY(dateValue[,style])
1148
     *
1149
     * @param    int    $dateValue        Excel date serial value (float), PHP date timestamp (integer),
1150
     *                                    PHP DateTime object, or a standard date string
1151
     * @param    int        $style            A number that determines the type of return value
1152
     *                                        1 or omitted    Numbers 1 (Sunday) through 7 (Saturday).
1153
     *                                        2                Numbers 1 (Monday) through 7 (Sunday).
1154
     *                                        3                Numbers 0 (Monday) through 6 (Sunday).
1155
     * @return    int        Day of the week value
1156
     */
1157 57
    public static function WEEKDAY($dateValue = 1, $style = 1)
1158
    {
1159 57
        $dateValue = Functions::flattenSingleValue($dateValue);
1160 57
        $style = Functions::flattenSingleValue($style);
1161
1162 57
        if (!is_numeric($style)) {
1163 1
            return Functions::VALUE();
1164 56
        } elseif (($style < 1) || ($style > 3)) {
1165 1
            return Functions::NAN();
1166
        }
1167 55
        $style = floor($style);
1168
1169 55
        if ($dateValue === null) {
1170
            $dateValue = 1;
1171 55
        } elseif (is_string($dateValue = self::getDateValue($dateValue))) {
1172 1
            return Functions::VALUE();
1173 54
        } elseif ($dateValue < 0.0) {
1174 1
            return Functions::NAN();
1175
        }
1176
1177
        // Execute function
1178 53
        $PHPDateObject = \PhpOffice\PhpSpreadsheet\Shared\Date::excelToDateTimeObject($dateValue);
1179 53
        $DoW = $PHPDateObject->format('w');
1180
1181 53
        $firstDay = 1;
1182
        switch ($style) {
1183 53
            case 1:
1184 8
                ++$DoW;
1185 8
                break;
1186 45
            case 2:
1187 26
                if ($DoW == 0) {
1188 3
                    $DoW = 7;
1189
                }
1190 26
                break;
1191 19
            case 3:
1192 19
                if ($DoW == 0) {
1193 3
                    $DoW = 7;
1194
                }
1195 19
                $firstDay = 0;
1196 19
                --$DoW;
1197 19
                break;
1198
        }
1199 53
        if (Functions::getCompatibilityMode() == Functions::COMPATIBILITY_EXCEL) {
1200
            //    Test for Excel's 1900 leap year, and introduce the error as required
1201 53
            if (($PHPDateObject->format('Y') == 1900) && ($PHPDateObject->format('n') <= 2)) {
1202 2
                --$DoW;
1203 2
                if ($DoW < $firstDay) {
1204 1
                    $DoW += 7;
1205
                }
1206
            }
1207
        }
1208
1209 53
        return (int) $DoW;
1210
    }
1211
1212
    /**
1213
     * WEEKNUM
1214
     *
1215
     * Returns the week of the year for a specified date.
1216
     * The WEEKNUM function considers the week containing January 1 to be the first week of the year.
1217
     * However, there is a European standard that defines the first week as the one with the majority
1218
     * of days (four or more) falling in the new year. This means that for years in which there are
1219
     * three days or less in the first week of January, the WEEKNUM function returns week numbers
1220
     * that are incorrect according to the European standard.
1221
     *
1222
     * Excel Function:
1223
     *        WEEKNUM(dateValue[,style])
1224
     *
1225
     * @param    mixed    $dateValue        Excel date serial value (float), PHP date timestamp (integer),
1226
     *                                    PHP DateTime object, or a standard date string
1227
     * @param    int    $method            Week begins on Sunday or Monday
1228
     *                                        1 or omitted    Week begins on Sunday.
1229
     *                                        2                Week begins on Monday.
1230
     * @return    int        Week Number
1231
     */
1232 15
    public static function WEEKNUM($dateValue = 1, $method = 1)
1233
    {
1234 15
        $dateValue = Functions::flattenSingleValue($dateValue);
1235 15
        $method = Functions::flattenSingleValue($method);
1236
1237 15 View Code Duplication
        if (!is_numeric($method)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1238 1
            return Functions::VALUE();
1239 14
        } elseif (($method < 1) || ($method > 2)) {
1240 1
            return Functions::NAN();
1241
        }
1242 13
        $method = floor($method);
1243
1244 13
        if ($dateValue === null) {
1245
            $dateValue = 1;
1246 13
        } elseif (is_string($dateValue = self::getDateValue($dateValue))) {
1247 1
            return Functions::VALUE();
1248 12
        } elseif ($dateValue < 0.0) {
1249 1
            return Functions::NAN();
1250
        }
1251
1252
        // Execute function
1253 11
        $PHPDateObject = \PhpOffice\PhpSpreadsheet\Shared\Date::excelToDateTimeObject($dateValue);
1254 11
        $dayOfYear = $PHPDateObject->format('z');
1255 11
        $PHPDateObject->modify('-' . $dayOfYear . ' days');
1256 11
        $firstDayOfFirstWeek = $PHPDateObject->format('w');
1257 11
        $daysInFirstWeek = (6 - $firstDayOfFirstWeek + $method) % 7;
1258 11
        $interval = $dayOfYear - $daysInFirstWeek;
1259 11
        $weekOfYear = floor($interval / 7) + 1;
1260
1261 11
        if ($daysInFirstWeek) {
1262 8
            ++$weekOfYear;
1263
        }
1264
1265 11
        return (int) $weekOfYear;
1266
    }
1267
1268
    /**
1269
     * MONTHOFYEAR
1270
     *
1271
     * Returns the month of a date represented by a serial number.
1272
     * The month is given as an integer, ranging from 1 (January) to 12 (December).
1273
     *
1274
     * Excel Function:
1275
     *        MONTH(dateValue)
1276
     *
1277
     * @param    mixed    $dateValue        Excel date serial value (float), PHP date timestamp (integer),
1278
     *                                    PHP DateTime object, or a standard date string
1279
     * @return    int        Month of the year
1280
     */
1281 21 View Code Duplication
    public static function MONTHOFYEAR($dateValue = 1)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1282
    {
1283 21
        $dateValue = Functions::flattenSingleValue($dateValue);
1284
1285 21
        if (empty($dateValue)) {
1286 2
            $dateValue = 1;
1287
        }
1288 21
        if (is_string($dateValue = self::getDateValue($dateValue))) {
1289 1
            return Functions::VALUE();
1290 20
        } elseif ($dateValue < 0.0) {
1291 1
            return Functions::NAN();
1292
        }
1293
1294
        // Execute function
1295 19
        $PHPDateObject = \PhpOffice\PhpSpreadsheet\Shared\Date::excelToDateTimeObject($dateValue);
1296
1297 19
        return (int) $PHPDateObject->format('n');
1298
    }
1299
1300
    /**
1301
     * YEAR
1302
     *
1303
     * Returns the year corresponding to a date.
1304
     * The year is returned as an integer in the range 1900-9999.
1305
     *
1306
     * Excel Function:
1307
     *        YEAR(dateValue)
1308
     *
1309
     * @param    mixed    $dateValue        Excel date serial value (float), PHP date timestamp (integer),
1310
     *                                    PHP DateTime object, or a standard date string
1311
     * @return    int        Year
1312
     */
1313 33 View Code Duplication
    public static function YEAR($dateValue = 1)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1314
    {
1315 33
        $dateValue = Functions::flattenSingleValue($dateValue);
1316
1317 33
        if ($dateValue === null) {
1318 1
            $dateValue = 1;
1319 32
        } elseif (is_string($dateValue = self::getDateValue($dateValue))) {
1320 1
            return Functions::VALUE();
1321 31
        } elseif ($dateValue < 0.0) {
1322 1
            return Functions::NAN();
1323
        }
1324
1325
        // Execute function
1326 31
        $PHPDateObject = \PhpOffice\PhpSpreadsheet\Shared\Date::excelToDateTimeObject($dateValue);
1327
1328 31
        return (int) $PHPDateObject->format('Y');
1329
    }
1330
1331
    /**
1332
     * HOUROFDAY
1333
     *
1334
     * Returns the hour of a time value.
1335
     * The hour is given as an integer, ranging from 0 (12:00 A.M.) to 23 (11:00 P.M.).
1336
     *
1337
     * Excel Function:
1338
     *        HOUR(timeValue)
1339
     *
1340
     * @param    mixed    $timeValue        Excel date serial value (float), PHP date timestamp (integer),
1341
     *                                    PHP DateTime object, or a standard time string
1342
     * @return    int        Hour
1343
     */
1344 12 View Code Duplication
    public static function HOUROFDAY($timeValue = 0)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1345
    {
1346 12
        $timeValue = Functions::flattenSingleValue($timeValue);
1347
1348 12
        if (!is_numeric($timeValue)) {
1349 4
            if (Functions::getCompatibilityMode() == Functions::COMPATIBILITY_GNUMERIC) {
1350
                $testVal = strtok($timeValue, '/-: ');
1351
                if (strlen($testVal) < strlen($timeValue)) {
1352
                    return Functions::VALUE();
1353
                }
1354
            }
1355 4
            $timeValue = self::getTimeValue($timeValue);
0 ignored issues
show
Bug introduced by
It seems like $timeValue defined by self::getTimeValue($timeValue) on line 1355 can also be of type boolean or null or object; however, PhpOffice\PhpSpreadsheet...ateTime::getTimeValue() does only seem to accept string, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
1356 4
            if (is_string($timeValue)) {
1357 1
                return Functions::VALUE();
1358
            }
1359
        }
1360
        // Execute function
1361 11
        if ($timeValue >= 1) {
1362 3
            $timeValue = fmod($timeValue, 1);
1363 8
        } elseif ($timeValue < 0.0) {
1364 1
            return Functions::NAN();
1365
        }
1366 10
        $timeValue = \PhpOffice\PhpSpreadsheet\Shared\Date::excelToTimestamp($timeValue);
1367
1368 10
        return (int) gmdate('G', $timeValue);
1369
    }
1370
1371
    /**
1372
     * MINUTE
1373
     *
1374
     * Returns the minutes of a time value.
1375
     * The minute is given as an integer, ranging from 0 to 59.
1376
     *
1377
     * Excel Function:
1378
     *        MINUTE(timeValue)
1379
     *
1380
     * @param    mixed    $timeValue        Excel date serial value (float), PHP date timestamp (integer),
1381
     *                                    PHP DateTime object, or a standard time string
1382
     * @return    int        Minute
1383
     */
1384 12 View Code Duplication
    public static function MINUTE($timeValue = 0)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1385
    {
1386 12
        $timeValue = $timeTester = Functions::flattenSingleValue($timeValue);
0 ignored issues
show
Unused Code introduced by
$timeTester is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
1387
1388 12
        if (!is_numeric($timeValue)) {
1389 4
            if (Functions::getCompatibilityMode() == Functions::COMPATIBILITY_GNUMERIC) {
1390
                $testVal = strtok($timeValue, '/-: ');
1391
                if (strlen($testVal) < strlen($timeValue)) {
1392
                    return Functions::VALUE();
1393
                }
1394
            }
1395 4
            $timeValue = self::getTimeValue($timeValue);
0 ignored issues
show
Bug introduced by
It seems like $timeValue defined by self::getTimeValue($timeValue) on line 1395 can also be of type boolean or null or object; however, PhpOffice\PhpSpreadsheet...ateTime::getTimeValue() does only seem to accept string, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
1396 4
            if (is_string($timeValue)) {
1397 1
                return Functions::VALUE();
1398
            }
1399
        }
1400
        // Execute function
1401 11
        if ($timeValue >= 1) {
1402 3
            $timeValue = fmod($timeValue, 1);
1403 8
        } elseif ($timeValue < 0.0) {
1404 1
            return Functions::NAN();
1405
        }
1406 10
        $timeValue = \PhpOffice\PhpSpreadsheet\Shared\Date::excelToTimestamp($timeValue);
1407
1408 10
        return (int) gmdate('i', $timeValue);
1409
    }
1410
1411
    /**
1412
     * SECOND
1413
     *
1414
     * Returns the seconds of a time value.
1415
     * The second is given as an integer in the range 0 (zero) to 59.
1416
     *
1417
     * Excel Function:
1418
     *        SECOND(timeValue)
1419
     *
1420
     * @param    mixed    $timeValue        Excel date serial value (float), PHP date timestamp (integer),
1421
     *                                    PHP DateTime object, or a standard time string
1422
     * @return    int        Second
1423
     */
1424 12 View Code Duplication
    public static function SECOND($timeValue = 0)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1425
    {
1426 12
        $timeValue = Functions::flattenSingleValue($timeValue);
1427
1428 12
        if (!is_numeric($timeValue)) {
1429 4
            if (Functions::getCompatibilityMode() == Functions::COMPATIBILITY_GNUMERIC) {
1430
                $testVal = strtok($timeValue, '/-: ');
1431
                if (strlen($testVal) < strlen($timeValue)) {
1432
                    return Functions::VALUE();
1433
                }
1434
            }
1435 4
            $timeValue = self::getTimeValue($timeValue);
0 ignored issues
show
Bug introduced by
It seems like $timeValue defined by self::getTimeValue($timeValue) on line 1435 can also be of type boolean or null or object; however, PhpOffice\PhpSpreadsheet...ateTime::getTimeValue() does only seem to accept string, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
1436 4
            if (is_string($timeValue)) {
1437 1
                return Functions::VALUE();
1438
            }
1439
        }
1440
        // Execute function
1441 11
        if ($timeValue >= 1) {
1442 3
            $timeValue = fmod($timeValue, 1);
1443 8
        } elseif ($timeValue < 0.0) {
1444 1
            return Functions::NAN();
1445
        }
1446 10
        $timeValue = \PhpOffice\PhpSpreadsheet\Shared\Date::excelToTimestamp($timeValue);
1447
1448 10
        return (int) gmdate('s', $timeValue);
1449
    }
1450
1451
    /**
1452
     * EDATE
1453
     *
1454
     * Returns the serial number that represents the date that is the indicated number of months
1455
     * before or after a specified date (the start_date).
1456
     * Use EDATE to calculate maturity dates or due dates that fall on the same day of the month
1457
     * as the date of issue.
1458
     *
1459
     * Excel Function:
1460
     *        EDATE(dateValue,adjustmentMonths)
1461
     *
1462
     * @param    mixed    $dateValue            Excel date serial value (float), PHP date timestamp (integer),
1463
     *                                        PHP DateTime object, or a standard date string
1464
     * @param    int        $adjustmentMonths    The number of months before or after start_date.
1465
     *                                        A positive value for months yields a future date;
1466
     *                                        a negative value yields a past date.
1467
     * @return    mixed    Excel date/time serial value, PHP date/time serial value or PHP date/time object,
1468
     *                        depending on the value of the ReturnDateType flag
1469
     */
1470 17
    public static function EDATE($dateValue = 1, $adjustmentMonths = 0)
1471
    {
1472 17
        $dateValue = Functions::flattenSingleValue($dateValue);
1473 17
        $adjustmentMonths = Functions::flattenSingleValue($adjustmentMonths);
1474
1475 17
        if (!is_numeric($adjustmentMonths)) {
1476 1
            return Functions::VALUE();
1477
        }
1478 16
        $adjustmentMonths = floor($adjustmentMonths);
1479
1480 16
        if (is_string($dateValue = self::getDateValue($dateValue))) {
1481 1
            return Functions::VALUE();
1482
        }
1483
1484
        // Execute function
1485 15
        $PHPDateObject = self::adjustDateByMonths($dateValue, $adjustmentMonths);
1486
1487 15 View Code Duplication
        switch (Functions::getReturnDateType()) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1488 15
            case Functions::RETURNDATE_EXCEL:
1489 13
                return (float) \PhpOffice\PhpSpreadsheet\Shared\Date::PHPToExcel($PHPDateObject);
0 ignored issues
show
Documentation introduced by
$PHPDateObject is of type object<DateTime>, but the function expects a integer.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
1490 2
            case Functions::RETURNDATE_PHP_NUMERIC:
1491 1
                return (integer) \PhpOffice\PhpSpreadsheet\Shared\Date::excelToTimestamp(\PhpOffice\PhpSpreadsheet\Shared\Date::PHPToExcel($PHPDateObject));
0 ignored issues
show
Documentation introduced by
$PHPDateObject is of type object<DateTime>, but the function expects a integer.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
Documentation introduced by
\PhpOffice\PhpSpreadshee...ToExcel($PHPDateObject) is of type double|false, but the function expects a integer.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
1492 1
            case Functions::RETURNDATE_PHP_OBJECT:
1493 1
                return $PHPDateObject;
1494
        }
1495
    }
1496
1497
    /**
1498
     * EOMONTH
1499
     *
1500
     * Returns the date value for the last day of the month that is the indicated number of months
1501
     * before or after start_date.
1502
     * Use EOMONTH to calculate maturity dates or due dates that fall on the last day of the month.
1503
     *
1504
     * Excel Function:
1505
     *        EOMONTH(dateValue,adjustmentMonths)
1506
     *
1507
     * @param    mixed    $dateValue            Excel date serial value (float), PHP date timestamp (integer),
1508
     *                                        PHP DateTime object, or a standard date string
1509
     * @param    int        $adjustmentMonths    The number of months before or after start_date.
1510
     *                                        A positive value for months yields a future date;
1511
     *                                        a negative value yields a past date.
1512
     * @return    mixed    Excel date/time serial value, PHP date/time serial value or PHP date/time object,
1513
     *                        depending on the value of the ReturnDateType flag
1514
     */
1515 19
    public static function EOMONTH($dateValue = 1, $adjustmentMonths = 0)
1516
    {
1517 19
        $dateValue = Functions::flattenSingleValue($dateValue);
1518 19
        $adjustmentMonths = Functions::flattenSingleValue($adjustmentMonths);
1519
1520 19
        if (!is_numeric($adjustmentMonths)) {
1521 1
            return Functions::VALUE();
1522
        }
1523 18
        $adjustmentMonths = floor($adjustmentMonths);
1524
1525 18
        if (is_string($dateValue = self::getDateValue($dateValue))) {
1526 1
            return Functions::VALUE();
1527
        }
1528
1529
        // Execute function
1530 17
        $PHPDateObject = self::adjustDateByMonths($dateValue, $adjustmentMonths + 1);
1531 17
        $adjustDays = (int) $PHPDateObject->format('d');
1532 17
        $adjustDaysString = '-' . $adjustDays . ' days';
1533 17
        $PHPDateObject->modify($adjustDaysString);
1534
1535 17 View Code Duplication
        switch (Functions::getReturnDateType()) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1536 17
            case Functions::RETURNDATE_EXCEL:
1537 15
                return (float) \PhpOffice\PhpSpreadsheet\Shared\Date::PHPToExcel($PHPDateObject);
0 ignored issues
show
Documentation introduced by
$PHPDateObject is of type object<DateTime>, but the function expects a integer.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
1538 2
            case Functions::RETURNDATE_PHP_NUMERIC:
1539 1
                return (integer) \PhpOffice\PhpSpreadsheet\Shared\Date::excelToTimestamp(\PhpOffice\PhpSpreadsheet\Shared\Date::PHPToExcel($PHPDateObject));
0 ignored issues
show
Documentation introduced by
$PHPDateObject is of type object<DateTime>, but the function expects a integer.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
Documentation introduced by
\PhpOffice\PhpSpreadshee...ToExcel($PHPDateObject) is of type double|false, but the function expects a integer.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
1540 1
            case Functions::RETURNDATE_PHP_OBJECT:
1541 1
                return $PHPDateObject;
1542
        }
1543
    }
1544
}
1545