Completed
Push — develop ( e1f81f...539a89 )
by Adrien
16:11
created

DateTime::DAYOFWEEK()   C

Complexity

Conditions 16
Paths 52

Size

Total Lines 54
Code Lines 37

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 16
eloc 37
nc 52
nop 2
dl 0
loc 54
rs 6.6856
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

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

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

Commonly applied refactorings include:

1
<?php
2
3
namespace 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    integer    $year    The year to test
33
     * @return    boolean            TRUE if the year is a leap year, otherwise FALSE
34
     */
35
    public static function isLeapYear($year)
36
    {
37
        return ((($year % 4) == 0) && (($year % 100) != 0) || (($year % 400) == 0));
38
    }
39
40
41
    /**
42
     * Return the number of days between two dates based on a 360 day calendar
43
     *
44
     * @param    integer    $startDay        Day of month of the start date
45
     * @param    integer    $startMonth        Month of the start date
46
     * @param    integer    $startYear        Year of the start date
47
     * @param    integer    $endDay            Day of month of the start date
48
     * @param    integer    $endMonth        Month of the start date
49
     * @param    integer    $endYear        Year of the start date
50
     * @param    boolean $methodUS        Whether to use the US method or the European method of calculation
51
     * @return    integer    Number of days between the start date and the end date
52
     */
53
    private static function dateDiff360($startDay, $startMonth, $startYear, $endDay, $endMonth, $endYear, $methodUS)
54
    {
55
        if ($startDay == 31) {
56
            --$startDay;
57
        } elseif ($methodUS && ($startMonth == 2 && ($startDay == 29 || ($startDay == 28 && !self::isLeapYear($startYear))))) {
58
            $startDay = 30;
59
        }
60
        if ($endDay == 31) {
61
            if ($methodUS && $startDay != 30) {
62
                $endDay = 1;
63
                if ($endMonth == 12) {
64
                    ++$endYear;
65
                    $endMonth = 1;
66
                } else {
67
                    ++$endMonth;
68
                }
69
            } else {
70
                $endDay = 30;
71
            }
72
        }
73
74
        return $endDay + $endMonth * 30 + $endYear * 360 - $startDay - $startMonth * 30 - $startYear * 360;
75
    }
76
77
78
    /**
79
     * getDateValue
80
     *
81
     * @param    string    $dateValue
82
     * @return    mixed    Excel date/time serial value, or string if error
83
     */
84
    public static function getDateValue($dateValue)
85
    {
86
        if (!is_numeric($dateValue)) {
87
            if ((is_string($dateValue)) &&
88
                (Functions::getCompatibilityMode() == Functions::COMPATIBILITY_GNUMERIC)) {
89
                return Functions::VALUE();
90
            }
91
            if ((is_object($dateValue)) && ($dateValue instanceof \DateTime)) {
92
                $dateValue = \PhpSpreadsheet\Shared\Date::PHPToExcel($dateValue);
93
            } else {
94
                $saveReturnDateType = Functions::getReturnDateType();
95
                Functions::setReturnDateType(Functions::RETURNDATE_EXCEL);
96
                $dateValue = self::DATEVALUE($dateValue);
97
                Functions::setReturnDateType($saveReturnDateType);
98
            }
99
        }
100
        return $dateValue;
101
    }
102
103
104
    /**
105
     * getTimeValue
106
     *
107
     * @param    string    $timeValue
108
     * @return    mixed    Excel date/time serial value, or string if error
109
     */
110
    private static function getTimeValue($timeValue)
111
    {
112
        $saveReturnDateType = Functions::getReturnDateType();
113
        Functions::setReturnDateType(Functions::RETURNDATE_EXCEL);
114
        $timeValue = self::TIMEVALUE($timeValue);
115
        Functions::setReturnDateType($saveReturnDateType);
116
        return $timeValue;
117
    }
118
119
120
    private static function adjustDateByMonths($dateValue = 0, $adjustmentMonths = 0)
121
    {
122
        // Execute function
123
        $PHPDateObject = \PhpSpreadsheet\Shared\Date::excelToDateTimeObject($dateValue);
124
        $oMonth = (int) $PHPDateObject->format('m');
125
        $oYear = (int) $PHPDateObject->format('Y');
126
127
        $adjustmentMonthsString = (string) $adjustmentMonths;
128
        if ($adjustmentMonths > 0) {
129
            $adjustmentMonthsString = '+'.$adjustmentMonths;
130
        }
131
        if ($adjustmentMonths != 0) {
132
            $PHPDateObject->modify($adjustmentMonthsString.' months');
133
        }
134
        $nMonth = (int) $PHPDateObject->format('m');
135
        $nYear = (int) $PHPDateObject->format('Y');
136
137
        $monthDiff = ($nMonth - $oMonth) + (($nYear - $oYear) * 12);
138
        if ($monthDiff != $adjustmentMonths) {
139
            $adjustDays = (int) $PHPDateObject->format('d');
140
            $adjustDaysString = '-'.$adjustDays.' days';
141
            $PHPDateObject->modify($adjustDaysString);
142
        }
143
        return $PHPDateObject;
144
    }
145
146
147
    /**
148
     * DATETIMENOW
149
     *
150
     * Returns the current date and time.
151
     * The NOW function is useful when you need to display the current date and time on a worksheet or
152
     * calculate a value based on the current date and time, and have that value updated each time you
153
     * open the worksheet.
154
     *
155
     * NOTE: When used in a Cell Formula, MS Excel changes the cell format so that it matches the date
156
     * and time format of your regional settings. PhpSpreadsheet does not change cell formatting in this way.
157
     *
158
     * Excel Function:
159
     *        NOW()
160
     *
161
     * @access    public
162
     * @category Date/Time Functions
163
     * @return    mixed    Excel date/time serial value, PHP date/time serial value or PHP date/time object,
164
     *                        depending on the value of the ReturnDateType flag
165
     */
166
    public static function DATETIMENOW()
167
    {
168
        $saveTimeZone = date_default_timezone_get();
169
        date_default_timezone_set('UTC');
170
        $retValue = false;
171
        switch (Functions::getReturnDateType()) {
172
            case Functions::RETURNDATE_EXCEL:
173
                $retValue = (float) \PhpSpreadsheet\Shared\Date::PHPToExcel(time());
174
                break;
175
            case Functions::RETURNDATE_PHP_NUMERIC:
176
                $retValue = (integer) time();
177
                break;
178
            case Functions::RETURNDATE_PHP_OBJECT:
179
                $retValue = new \DateTime();
180
                break;
181
        }
182
        date_default_timezone_set($saveTimeZone);
183
184
        return $retValue;
185
    }
186
187
188
    /**
189
     * DATENOW
190
     *
191
     * Returns the current date.
192
     * The NOW function is useful when you need to display the current date and time on a worksheet or
193
     * calculate a value based on the current date and time, and have that value updated each time you
194
     * open the worksheet.
195
     *
196
     * NOTE: When used in a Cell Formula, MS Excel changes the cell format so that it matches the date
197
     * and time format of your regional settings. PhpSpreadsheet does not change cell formatting in this way.
198
     *
199
     * Excel Function:
200
     *        TODAY()
201
     *
202
     * @access    public
203
     * @category Date/Time Functions
204
     * @return    mixed    Excel date/time serial value, PHP date/time serial value or PHP date/time object,
205
     *                        depending on the value of the ReturnDateType flag
206
     */
207
    public static function DATENOW()
208
    {
209
        $saveTimeZone = date_default_timezone_get();
210
        date_default_timezone_set('UTC');
211
        $retValue = false;
212
        $excelDateTime = floor(\PhpSpreadsheet\Shared\Date::PHPToExcel(time()));
213
        switch (Functions::getReturnDateType()) {
214
            case Functions::RETURNDATE_EXCEL:
215
                $retValue = (float) $excelDateTime;
216
                break;
217
            case Functions::RETURNDATE_PHP_NUMERIC:
218
                $retValue = (integer) \PhpSpreadsheet\Shared\Date::excelToTimestamp($excelDateTime);
219
                break;
220
            case Functions::RETURNDATE_PHP_OBJECT:
221
                $retValue = \PhpSpreadsheet\Shared\Date::excelToDateTimeObject($excelDateTime);
222
                break;
223
        }
224
        date_default_timezone_set($saveTimeZone);
225
226
        return $retValue;
227
    }
228
229
230
    /**
231
     * DATE
232
     *
233
     * The DATE function returns a value that represents a particular date.
234
     *
235
     * NOTE: When used in a Cell Formula, MS Excel changes the cell format so that it matches the date
236
     * format of your regional settings. PhpSpreadsheet does not change cell formatting in this way.
237
     *
238
     * Excel Function:
239
     *        DATE(year,month,day)
240
     *
241
     * PhpSpreadsheet is a lot more forgiving than MS Excel when passing non numeric values to this function.
242
     * A Month name or abbreviation (English only at this point) such as 'January' or 'Jan' will still be accepted,
243
     *     as will a day value with a suffix (e.g. '21st' rather than simply 21); again only English language.
244
     *
245
     * @access    public
246
     * @category Date/Time Functions
247
     * @param    integer        $year    The value of the year argument can include one to four digits.
248
     *                                Excel interprets the year argument according to the configured
249
     *                                date system: 1900 or 1904.
250
     *                                If year is between 0 (zero) and 1899 (inclusive), Excel adds that
251
     *                                value to 1900 to calculate the year. For example, DATE(108,1,2)
252
     *                                returns January 2, 2008 (1900+108).
253
     *                                If year is between 1900 and 9999 (inclusive), Excel uses that
254
     *                                value as the year. For example, DATE(2008,1,2) returns January 2,
255
     *                                2008.
256
     *                                If year is less than 0 or is 10000 or greater, Excel returns the
257
     *                                #NUM! error value.
258
     * @param    integer        $month    A positive or negative integer representing the month of the year
259
     *                                from 1 to 12 (January to December).
260
     *                                If month is greater than 12, month adds that number of months to
261
     *                                the first month in the year specified. For example, DATE(2008,14,2)
262
     *                                returns the serial number representing February 2, 2009.
263
     *                                If month is less than 1, month subtracts the magnitude of that
264
     *                                number of months, plus 1, from the first month in the year
265
     *                                specified. For example, DATE(2008,-3,2) returns the serial number
266
     *                                representing September 2, 2007.
267
     * @param    integer        $day    A positive or negative integer representing the day of the month
268
     *                                from 1 to 31.
269
     *                                If day is greater than the number of days in the month specified,
270
     *                                day adds that number of days to the first day in the month. For
271
     *                                example, DATE(2008,1,35) returns the serial number representing
272
     *                                February 4, 2008.
273
     *                                If day is less than 1, day subtracts the magnitude that number of
274
     *                                days, plus one, from the first day of the month specified. For
275
     *                                example, DATE(2008,1,-15) returns the serial number representing
276
     *                                December 16, 2007.
277
     * @return    mixed    Excel date/time serial value, PHP date/time serial value or PHP date/time object,
278
     *                        depending on the value of the ReturnDateType flag
279
     */
280
    public static function DATE($year = 0, $month = 1, $day = 1)
281
    {
282
        $year  = Functions::flattenSingleValue($year);
283
        $month = Functions::flattenSingleValue($month);
284
        $day   = Functions::flattenSingleValue($day);
285
286
        if (($month !== null) && (!is_numeric($month))) {
287
            $month = \PhpSpreadsheet\Shared\Date::monthStringToNumber($month);
0 ignored issues
show
Bug introduced by
It seems like $month defined by \PhpSpreadsheet\Shared\D...hStringToNumber($month) on line 287 can also be of type boolean or object; however, PhpSpreadsheet\Shared\Date::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...
288
        }
289
290
        if (($day !== null) && (!is_numeric($day))) {
291
            $day = \PhpSpreadsheet\Shared\Date::dayStringToNumber($day);
0 ignored issues
show
Bug introduced by
It seems like $day defined by \PhpSpreadsheet\Shared\D...dayStringToNumber($day) on line 291 can also be of type boolean or object; however, PhpSpreadsheet\Shared\Date::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...
292
        }
293
294
        $year = ($year !== null) ? \PhpSpreadsheet\Shared\StringHelper::testStringAsNumeric($year) : 0;
295
        $month = ($month !== null) ? \PhpSpreadsheet\Shared\StringHelper::testStringAsNumeric($month) : 0;
296
        $day = ($day !== null) ? \PhpSpreadsheet\Shared\StringHelper::testStringAsNumeric($day) : 0;
297
        if ((!is_numeric($year)) ||
298
            (!is_numeric($month)) ||
299
            (!is_numeric($day))) {
300
            return Functions::VALUE();
301
        }
302
        $year    = (integer) $year;
303
        $month    = (integer) $month;
304
        $day    = (integer) $day;
305
306
        $baseYear = \PhpSpreadsheet\Shared\Date::getExcelCalendar();
307
        // Validate parameters
308
        if ($year < ($baseYear-1900)) {
309
            return Functions::NAN();
310
        }
311
        if ((($baseYear-1900) != 0) && ($year < $baseYear) && ($year >= 1900)) {
312
            return Functions::NAN();
313
        }
314
315
        if (($year < $baseYear) && ($year >= ($baseYear-1900))) {
316
            $year += 1900;
317
        }
318
319
        if ($month < 1) {
320
            //    Handle year/month adjustment if month < 1
321
            --$month;
322
            $year += ceil($month / 12) - 1;
323
            $month = 13 - abs($month % 12);
324
        } elseif ($month > 12) {
325
            //    Handle year/month adjustment if month > 12
326
            $year += floor($month / 12);
327
            $month = ($month % 12);
328
        }
329
330
        // Re-validate the year parameter after adjustments
331
        if (($year < $baseYear) || ($year >= 10000)) {
332
            return Functions::NAN();
333
        }
334
335
        // Execute function
336
        $excelDateValue = \PhpSpreadsheet\Shared\Date::formattedPHPToExcel($year, $month, $day);
337 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...
338
            case Functions::RETURNDATE_EXCEL:
339
                return (float) $excelDateValue;
340
            case Functions::RETURNDATE_PHP_NUMERIC:
341
                return (integer) \PhpSpreadsheet\Shared\Date::excelToTimestamp($excelDateValue);
342
            case Functions::RETURNDATE_PHP_OBJECT:
343
                return \PhpSpreadsheet\Shared\Date::excelToDateTimeObject($excelDateValue);
344
        }
345
    }
346
347
348
    /**
349
     * TIME
350
     *
351
     * The TIME function returns a value that represents a particular time.
352
     *
353
     * NOTE: When used in a Cell Formula, MS Excel changes the cell format so that it matches the time
354
     * format of your regional settings. PhpSpreadsheet does not change cell formatting in this way.
355
     *
356
     * Excel Function:
357
     *        TIME(hour,minute,second)
358
     *
359
     * @access    public
360
     * @category Date/Time Functions
361
     * @param    integer        $hour        A number from 0 (zero) to 32767 representing the hour.
362
     *                                    Any value greater than 23 will be divided by 24 and the remainder
363
     *                                    will be treated as the hour value. For example, TIME(27,0,0) =
364
     *                                    TIME(3,0,0) = .125 or 3:00 AM.
365
     * @param    integer        $minute        A number from 0 to 32767 representing the minute.
366
     *                                    Any value greater than 59 will be converted to hours and minutes.
367
     *                                    For example, TIME(0,750,0) = TIME(12,30,0) = .520833 or 12:30 PM.
368
     * @param    integer        $second        A number from 0 to 32767 representing the second.
369
     *                                    Any value greater than 59 will be converted to hours, minutes,
370
     *                                    and seconds. For example, TIME(0,0,2000) = TIME(0,33,22) = .023148
371
     *                                    or 12:33:20 AM
372
     * @return    mixed    Excel date/time serial value, PHP date/time serial value or PHP date/time object,
373
     *                        depending on the value of the ReturnDateType flag
374
     */
375
    public static function TIME($hour = 0, $minute = 0, $second = 0)
376
    {
377
        $hour = Functions::flattenSingleValue($hour);
378
        $minute = Functions::flattenSingleValue($minute);
379
        $second = Functions::flattenSingleValue($second);
380
381
        if ($hour == '') {
382
            $hour = 0;
383
        }
384
        if ($minute == '') {
385
            $minute = 0;
386
        }
387
        if ($second == '') {
388
            $second = 0;
389
        }
390
391
        if ((!is_numeric($hour)) || (!is_numeric($minute)) || (!is_numeric($second))) {
392
            return Functions::VALUE();
393
        }
394
        $hour = (integer) $hour;
395
        $minute = (integer) $minute;
396
        $second = (integer) $second;
397
398 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...
399
            $minute += floor($second / 60);
400
            $second = 60 - abs($second % 60);
401
            if ($second == 60) {
402
                $second = 0;
403
            }
404
        } elseif ($second >= 60) {
405
            $minute += floor($second / 60);
406
            $second = $second % 60;
407
        }
408 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...
409
            $hour += floor($minute / 60);
410
            $minute = 60 - abs($minute % 60);
411
            if ($minute == 60) {
412
                $minute = 0;
413
            }
414
        } elseif ($minute >= 60) {
415
            $hour += floor($minute / 60);
416
            $minute = $minute % 60;
417
        }
418
419
        if ($hour > 23) {
420
            $hour = $hour % 24;
421
        } elseif ($hour < 0) {
422
            return Functions::NAN();
423
        }
424
425
        // Execute function
426
        switch (Functions::getReturnDateType()) {
427
            case Functions::RETURNDATE_EXCEL:
428
                $date = 0;
429
                $calendar = \PhpSpreadsheet\Shared\Date::getExcelCalendar();
430
                if ($calendar != \PhpSpreadsheet\Shared\Date::CALENDAR_WINDOWS_1900) {
431
                    $date = 1;
432
                }
433
                return (float) \PhpSpreadsheet\Shared\Date::formattedPHPToExcel($calendar, 1, $date, $hour, $minute, $second);
434
            case Functions::RETURNDATE_PHP_NUMERIC:
435
                return (integer) \PhpSpreadsheet\Shared\Date::excelToTimestamp(\PhpSpreadsheet\Shared\Date::formattedPHPToExcel(1970, 1, 1, $hour, $minute, $second));    // -2147468400; //    -2147472000 + 3600
436
            case Functions::RETURNDATE_PHP_OBJECT:
437
                $dayAdjust = 0;
438 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...
439
                    $dayAdjust = floor($hour / 24);
440
                    $hour = 24 - abs($hour % 24);
441
                    if ($hour == 24) {
442
                        $hour = 0;
443
                    }
444
                } elseif ($hour >= 24) {
445
                    $dayAdjust = floor($hour / 24);
446
                    $hour = $hour % 24;
447
                }
448
                $phpDateObject = new \DateTime('1900-01-01 '.$hour.':'.$minute.':'.$second);
449
                if ($dayAdjust != 0) {
450
                    $phpDateObject->modify($dayAdjust.' days');
451
                }
452
                return $phpDateObject;
453
        }
454
    }
455
456
457
    /**
458
     * DATEVALUE
459
     *
460
     * Returns a value that represents a particular date.
461
     * Use DATEVALUE to convert a date represented by a text string to an Excel or PHP date/time stamp
462
     * value.
463
     *
464
     * NOTE: When used in a Cell Formula, MS Excel changes the cell format so that it matches the date
465
     * format of your regional settings. PhpSpreadsheet does not change cell formatting in this way.
466
     *
467
     * Excel Function:
468
     *        DATEVALUE(dateValue)
469
     *
470
     * @access    public
471
     * @category Date/Time Functions
472
     * @param    string    $dateValue        Text that represents a date in a Microsoft Excel date format.
473
     *                                    For example, "1/30/2008" or "30-Jan-2008" are text strings within
474
     *                                    quotation marks that represent dates. Using the default date
475
     *                                    system in Excel for Windows, date_text must represent a date from
476
     *                                    January 1, 1900, to December 31, 9999. Using the default date
477
     *                                    system in Excel for the Macintosh, date_text must represent a date
478
     *                                    from January 1, 1904, to December 31, 9999. DATEVALUE returns the
479
     *                                    #VALUE! error value if date_text is out of this range.
480
     * @return    mixed    Excel date/time serial value, PHP date/time serial value or PHP date/time object,
481
     *                        depending on the value of the ReturnDateType flag
482
     */
483
    public static function DATEVALUE($dateValue = 1)
484
    {
485
        $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...
486
        $dateValue = trim(Functions::flattenSingleValue($dateValue), '"');
487
        //    Strip any ordinals because they're allowed in Excel (English only)
488
        $dateValue = preg_replace('/(\d)(st|nd|rd|th)([ -\/])/Ui', '$1$3', $dateValue);
489
        //    Convert separators (/ . or space) to hyphens (should also handle dot used for ordinals in some countries, e.g. Denmark, Germany)
490
        $dateValue    = str_replace(array('/', '.', '-', '  '), array(' ', ' ', ' ', ' '), $dateValue);
491
492
        $yearFound = false;
493
        $t1 = explode(' ', $dateValue);
494
        foreach ($t1 as &$t) {
495
            if ((is_numeric($t)) && ($t > 31)) {
496
                if ($yearFound) {
497
                    return Functions::VALUE();
498
                } else {
499
                    if ($t < 100) {
500
                        $t += 1900;
501
                    }
502
                    $yearFound = true;
503
                }
504
            }
505
        }
506
        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...
507
            //    We've been fed a time value without any date
508
            return 0.0;
509
        } elseif (count($t1) == 2) {
510
            //    We only have two parts of the date: either day/month or month/year
511
            if ($yearFound) {
512
                array_unshift($t1, 1);
513
            } else {
514
                if ($t1[1] > 29) {
515
                    $t1[1] += 1900;
516
                    array_unshift($t1, 1);
517
                } else {
518
                    array_push($t1, date('Y'));
519
                }
520
            }
521
        }
522
        unset($t);
523
        $dateValue = implode(' ', $t1);
524
525
        $PHPDateArray = date_parse($dateValue);
526
        if (($PHPDateArray === false) || ($PHPDateArray['error_count'] > 0)) {
527
            $testVal1 = strtok($dateValue, '- ');
528
            if ($testVal1 !== false) {
529
                $testVal2 = strtok('- ');
530
                if ($testVal2 !== false) {
531
                    $testVal3 = strtok('- ');
532
                    if ($testVal3 === false) {
533
                        $testVal3 = strftime('%Y');
534
                    }
535
                } else {
536
                    return Functions::VALUE();
537
                }
538
            } else {
539
                return Functions::VALUE();
540
            }
541
            if ($testVal1 < 31 && $testVal2 < 12 && $testVal3 < 12 && strlen($testVal3) == 2) {
542
                $testVal3 += 2000;
543
            }
544
            $PHPDateArray = date_parse($testVal1.'-'.$testVal2.'-'.$testVal3);
545
            if (($PHPDateArray === false) || ($PHPDateArray['error_count'] > 0)) {
546
                $PHPDateArray = date_parse($testVal2.'-'.$testVal1.'-'.$testVal3);
547
                if (($PHPDateArray === false) || ($PHPDateArray['error_count'] > 0)) {
548
                    return Functions::VALUE();
549
                }
550
            }
551
        }
552
553
        if (($PHPDateArray !== false) && ($PHPDateArray['error_count'] == 0)) {
554
            // Execute function
555
            if ($PHPDateArray['year'] == '') {
556
                $PHPDateArray['year'] = strftime('%Y');
557
            }
558
            if ($PHPDateArray['year'] < 1900) {
559
                return Functions::VALUE();
560
            }
561
            if ($PHPDateArray['month'] == '') {
562
                $PHPDateArray['month'] = strftime('%m');
563
            }
564
            if ($PHPDateArray['day'] == '') {
565
                $PHPDateArray['day'] = strftime('%d');
566
            }
567
            if (!checkdate($PHPDateArray['month'], $PHPDateArray['day'], $PHPDateArray['year'])) {
568
                return Functions::VALUE();
569
            }
570
            $excelDateValue = floor(
571
                \PhpSpreadsheet\Shared\Date::formattedPHPToExcel(
572
                    $PHPDateArray['year'],
573
                    $PHPDateArray['month'],
574
                    $PHPDateArray['day'],
575
                    $PHPDateArray['hour'],
576
                    $PHPDateArray['minute'],
577
                    $PHPDateArray['second']
578
                )
579
            );
580 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...
581
                case Functions::RETURNDATE_EXCEL:
582
                    return (float) $excelDateValue;
583
                case Functions::RETURNDATE_PHP_NUMERIC:
584
                    return (integer) \PhpSpreadsheet\Shared\Date::excelToTimestamp($excelDateValue);
585
                case Functions::RETURNDATE_PHP_OBJECT:
586
                    return new \DateTime($PHPDateArray['year'].'-'.$PHPDateArray['month'].'-'.$PHPDateArray['day'].' 00:00:00');
587
            }
588
        }
589
        return Functions::VALUE();
590
    }
591
592
593
    /**
594
     * TIMEVALUE
595
     *
596
     * Returns a value that represents a particular time.
597
     * Use TIMEVALUE to convert a time represented by a text string to an Excel or PHP date/time stamp
598
     * value.
599
     *
600
     * NOTE: When used in a Cell Formula, MS Excel changes the cell format so that it matches the time
601
     * format of your regional settings. PhpSpreadsheet does not change cell formatting in this way.
602
     *
603
     * Excel Function:
604
     *        TIMEVALUE(timeValue)
605
     *
606
     * @access    public
607
     * @category Date/Time Functions
608
     * @param    string    $timeValue        A text string that represents a time in any one of the Microsoft
609
     *                                    Excel time formats; for example, "6:45 PM" and "18:45" text strings
610
     *                                    within quotation marks that represent time.
611
     *                                    Date information in time_text is ignored.
612
     * @return    mixed    Excel date/time serial value, PHP date/time serial value or PHP date/time object,
613
     *                        depending on the value of the ReturnDateType flag
614
     */
615
    public static function TIMEVALUE($timeValue)
616
    {
617
        $timeValue = trim(Functions::flattenSingleValue($timeValue), '"');
618
        $timeValue = str_replace(array('/', '.'), array('-', '-'), $timeValue);
619
620
        $arraySplit = preg_split('/[\/:\-\s]/', $timeValue);
621
        if ((count($arraySplit) == 2 ||count($arraySplit) == 3) && $arraySplit[0] > 24) {
622
            $arraySplit[0] = ($arraySplit[0] % 24);
623
            $timeValue = implode(':', $arraySplit);
624
        }
625
626
        $PHPDateArray = date_parse($timeValue);
627
        if (($PHPDateArray !== false) && ($PHPDateArray['error_count'] == 0)) {
628
            if (Functions::getCompatibilityMode() == Functions::COMPATIBILITY_OPENOFFICE) {
629
                $excelDateValue = \PhpSpreadsheet\Shared\Date::formattedPHPToExcel(
630
                    $PHPDateArray['year'],
631
                    $PHPDateArray['month'],
632
                    $PHPDateArray['day'],
633
                    $PHPDateArray['hour'],
634
                    $PHPDateArray['minute'],
635
                    $PHPDateArray['second']
636
                );
637
            } else {
638
                $excelDateValue = \PhpSpreadsheet\Shared\Date::formattedPHPToExcel(1900, 1, 1, $PHPDateArray['hour'], $PHPDateArray['minute'], $PHPDateArray['second']) - 1;
639
            }
640
641 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...
642
                case Functions::RETURNDATE_EXCEL:
643
                    return (float) $excelDateValue;
644
                case Functions::RETURNDATE_PHP_NUMERIC:
645
                    return (integer) $phpDateValue = \PhpSpreadsheet\Shared\Date::excelToTimestamp($excelDateValue+25569) - 3600;
646
                case Functions::RETURNDATE_PHP_OBJECT:
647
                    return new \DateTime('1900-01-01 '.$PHPDateArray['hour'].':'.$PHPDateArray['minute'].':'.$PHPDateArray['second']);
648
            }
649
        }
650
        return Functions::VALUE();
651
    }
652
653
654
    /**
655
     * DATEDIF
656
     *
657
     * @param    mixed    $startDate        Excel date serial value, PHP date/time stamp, PHP DateTime object
658
     *                                    or a standard date string
659
     * @param    mixed    $endDate        Excel date serial value, PHP date/time stamp, PHP DateTime object
660
     *                                    or a standard date string
661
     * @param    string    $unit
662
     * @return    integer    Interval between the dates
663
     */
664
    public static function DATEDIF($startDate = 0, $endDate = 0, $unit = 'D')
665
    {
666
        $startDate = Functions::flattenSingleValue($startDate);
667
        $endDate   = Functions::flattenSingleValue($endDate);
668
        $unit      = strtoupper(Functions::flattenSingleValue($unit));
669
670
        if (is_string($startDate = self::getDateValue($startDate))) {
671
            return Functions::VALUE();
672
        }
673
        if (is_string($endDate = self::getDateValue($endDate))) {
674
            return Functions::VALUE();
675
        }
676
677
        // Validate parameters
678
        if ($startDate >= $endDate) {
679
            return Functions::NAN();
680
        }
681
682
        // Execute function
683
        $difference = $endDate - $startDate;
684
685
        $PHPStartDateObject = \PhpSpreadsheet\Shared\Date::excelToDateTimeObject($startDate);
686
        $startDays = $PHPStartDateObject->format('j');
687
        $startMonths = $PHPStartDateObject->format('n');
688
        $startYears = $PHPStartDateObject->format('Y');
689
690
        $PHPEndDateObject = \PhpSpreadsheet\Shared\Date::excelToDateTimeObject($endDate);
691
        $endDays = $PHPEndDateObject->format('j');
692
        $endMonths = $PHPEndDateObject->format('n');
693
        $endYears = $PHPEndDateObject->format('Y');
694
695
        $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...
696
        switch ($unit) {
697
            case 'D':
698
                $retVal = intval($difference);
699
                break;
700 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...
701
                $retVal = intval($endMonths - $startMonths) + (intval($endYears - $startYears) * 12);
702
                //    We're only interested in full months
703
                if ($endDays < $startDays) {
704
                    --$retVal;
705
                }
706
                break;
707
            case 'Y':
708
                $retVal = intval($endYears - $startYears);
709
                //    We're only interested in full months
710
                if ($endMonths < $startMonths) {
711
                    --$retVal;
712
                } elseif (($endMonths == $startMonths) && ($endDays < $startDays)) {
713
                    // Remove start month
714
                    --$retVal;
715
                    // Remove end month
716
                    --$retVal;
717
                }
718
                break;
719
            case 'MD':
720
                if ($endDays < $startDays) {
721
                    $retVal = $endDays;
722
                    $PHPEndDateObject->modify('-'.$endDays.' days');
723
                    $adjustDays = $PHPEndDateObject->format('j');
724
                    $retVal += ($adjustDays - $startDays);
725
                } else {
726
                    $retVal = $endDays - $startDays;
727
                }
728
                break;
729 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...
730
                $retVal = intval($endMonths - $startMonths);
731
                if ($retVal < 0) {
732
                    $retVal += 12;
733
                }
734
                //    We're only interested in full months
735
                if ($endDays < $startDays) {
736
                    --$retVal;
737
                }
738
                break;
739
            case 'YD':
740
                $retVal = intval($difference);
741
                if ($endYears > $startYears) {
742
                    while ($endYears > $startYears) {
743
                        $PHPEndDateObject->modify('-1 year');
744
                        $endYears = $PHPEndDateObject->format('Y');
745
                    }
746
                    $retVal = $PHPEndDateObject->format('z') - $PHPStartDateObject->format('z');
747
                    if ($retVal < 0) {
748
                        $retVal += 365;
749
                    }
750
                }
751
                break;
752
            default:
753
                $retVal = Functions::VALUE();
754
        }
755
        return $retVal;
756
    }
757
758
759
    /**
760
     * DAYS360
761
     *
762
     * Returns the number of days between two dates based on a 360-day year (twelve 30-day months),
763
     * which is used in some accounting calculations. Use this function to help compute payments if
764
     * your accounting system is based on twelve 30-day months.
765
     *
766
     * Excel Function:
767
     *        DAYS360(startDate,endDate[,method])
768
     *
769
     * @access    public
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    boolean        $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    integer        Number of days between start date and end date
787
     */
788
    public static function DAYS360($startDate = 0, $endDate = 0, $method = false)
789
    {
790
        $startDate    = Functions::flattenSingleValue($startDate);
791
        $endDate    = Functions::flattenSingleValue($endDate);
792
793
        if (is_string($startDate = self::getDateValue($startDate))) {
794
            return Functions::VALUE();
795
        }
796
        if (is_string($endDate = self::getDateValue($endDate))) {
797
            return Functions::VALUE();
798
        }
799
800
        if (!is_bool($method)) {
801
            return Functions::VALUE();
802
        }
803
804
        // Execute function
805
        $PHPStartDateObject = \PhpSpreadsheet\Shared\Date::excelToDateTimeObject($startDate);
806
        $startDay = $PHPStartDateObject->format('j');
807
        $startMonth = $PHPStartDateObject->format('n');
808
        $startYear = $PHPStartDateObject->format('Y');
809
810
        $PHPEndDateObject = \PhpSpreadsheet\Shared\Date::excelToDateTimeObject($endDate);
811
        $endDay = $PHPEndDateObject->format('j');
812
        $endMonth = $PHPEndDateObject->format('n');
813
        $endYear = $PHPEndDateObject->format('Y');
814
815
        return self::dateDiff360($startDay, $startMonth, $startYear, $endDay, $endMonth, $endYear, !$method);
816
    }
817
818
819
    /**
820
     * YEARFRAC
821
     *
822
     * Calculates the fraction of the year represented by the number of whole days between two dates
823
     * (the start_date and the end_date).
824
     * Use the YEARFRAC worksheet function to identify the proportion of a whole year's benefits or
825
     * obligations to assign to a specific term.
826
     *
827
     * Excel Function:
828
     *        YEARFRAC(startDate,endDate[,method])
829
     *
830
     * @access    public
831
     * @category Date/Time Functions
832
     * @param    mixed    $startDate        Excel date serial value (float), PHP date timestamp (integer),
833
     *                                    PHP DateTime object, or a standard date string
834
     * @param    mixed    $endDate        Excel date serial value (float), PHP date timestamp (integer),
835
     *                                    PHP DateTime object, or a standard date string
836
     * @param    integer    $method            Method used for the calculation
837
     *                                        0 or omitted    US (NASD) 30/360
838
     *                                        1                Actual/actual
839
     *                                        2                Actual/360
840
     *                                        3                Actual/365
841
     *                                        4                European 30/360
842
     * @return    float    fraction of the year
843
     */
844
    public static function YEARFRAC($startDate = 0, $endDate = 0, $method = 0)
845
    {
846
        $startDate    = Functions::flattenSingleValue($startDate);
847
        $endDate    = Functions::flattenSingleValue($endDate);
848
        $method        = Functions::flattenSingleValue($method);
849
850
        if (is_string($startDate = self::getDateValue($startDate))) {
851
            return Functions::VALUE();
852
        }
853
        if (is_string($endDate = self::getDateValue($endDate))) {
854
            return Functions::VALUE();
855
        }
856
857
        if (((is_numeric($method)) && (!is_string($method))) || ($method == '')) {
858
            switch ($method) {
859
                case 0:
860
                    return self::DAYS360($startDate, $endDate) / 360;
861
                case 1:
862
                    $days = self::DATEDIF($startDate, $endDate);
863
                    $startYear = self::YEAR($startDate);
864
                    $endYear = self::YEAR($endDate);
865
                    $years = $endYear - $startYear + 1;
866
                    $leapDays = 0;
867
                    if ($years == 1) {
868
                        if (self::isLeapYear($endYear)) {
869
                            $startMonth = self::MONTHOFYEAR($startDate);
870
                            $endMonth = self::MONTHOFYEAR($endDate);
871
                            $endDay = self::DAYOFMONTH($endDate);
872
                            if (($startMonth < 3) ||
873
                                (($endMonth * 100 + $endDay) >= (2 * 100 + 29))) {
874
                                 $leapDays += 1;
875
                            }
876
                        }
877
                    } else {
878
                        for ($year = $startYear; $year <= $endYear; ++$year) {
879
                            if ($year == $startYear) {
880
                                $startMonth = self::MONTHOFYEAR($startDate);
881
                                $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...
882
                                if ($startMonth < 3) {
883
                                    $leapDays += (self::isLeapYear($year)) ? 1 : 0;
884
                                }
885
                            } elseif ($year == $endYear) {
886
                                $endMonth = self::MONTHOFYEAR($endDate);
887
                                $endDay = self::DAYOFMONTH($endDate);
888
                                if (($endMonth * 100 + $endDay) >= (2 * 100 + 29)) {
889
                                    $leapDays += (self::isLeapYear($year)) ? 1 : 0;
890
                                }
891
                            } else {
892
                                $leapDays += (self::isLeapYear($year)) ? 1 : 0;
893
                            }
894
                        }
895
                        if ($years == 2) {
896
                            if (($leapDays == 0) && (self::isLeapYear($startYear)) && ($days > 365)) {
897
                                $leapDays = 1;
898
                            } elseif ($days < 366) {
899
                                $years = 1;
900
                            }
901
                        }
902
                        $leapDays /= $years;
903
                    }
904
                    return $days / (365 + $leapDays);
905
                case 2:
906
                    return self::DATEDIF($startDate, $endDate) / 360;
907
                case 3:
908
                    return self::DATEDIF($startDate, $endDate) / 365;
909
                case 4:
910
                    return self::DAYS360($startDate, $endDate, true) / 360;
911
            }
912
        }
913
        return Functions::VALUE();
914
    }
915
916
917
    /**
918
     * NETWORKDAYS
919
     *
920
     * Returns the number of whole working days between start_date and end_date. Working days
921
     * exclude weekends and any dates identified in holidays.
922
     * Use NETWORKDAYS to calculate employee benefits that accrue based on the number of days
923
     * worked during a specific term.
924
     *
925
     * Excel Function:
926
     *        NETWORKDAYS(startDate,endDate[,holidays[,holiday[,...]]])
927
     *
928
     * @access    public
929
     * @category Date/Time Functions
930
     * @param    mixed            $startDate        Excel date serial value (float), PHP date timestamp (integer),
931
     *                                            PHP DateTime object, or a standard date string
932
     * @param    mixed            $endDate        Excel date serial value (float), PHP date timestamp (integer),
933
     *                                            PHP DateTime object, or a standard date string
934
     * @param    mixed            $holidays,...    Optional series of Excel date serial value (float), PHP date
0 ignored issues
show
Bug introduced by
There is no parameter named $holidays,.... Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
935
     *                                            timestamp (integer), PHP DateTime object, or a standard date
936
     *                                            strings that will be excluded from the working calendar, such
937
     *                                            as state and federal holidays and floating holidays.
938
     * @return    integer            Interval between the dates
939
     */
940
    public static function NETWORKDAYS($startDate, $endDate)
941
    {
942
        //    Retrieve the mandatory start and end date that are referenced in the function definition
943
        $startDate    = Functions::flattenSingleValue($startDate);
944
        $endDate    = Functions::flattenSingleValue($endDate);
945
        //    Flush the mandatory start and end date that are referenced in the function definition, and get the optional days
946
        $dateArgs = Functions::flattenArray(func_get_args());
947
        array_shift($dateArgs);
948
        array_shift($dateArgs);
949
950
        //    Validate the start and end dates
951
        if (is_string($startDate = $sDate = self::getDateValue($startDate))) {
952
            return Functions::VALUE();
953
        }
954
        $startDate = (float) floor($startDate);
955
        if (is_string($endDate = $eDate = self::getDateValue($endDate))) {
956
            return Functions::VALUE();
957
        }
958
        $endDate = (float) floor($endDate);
959
960
        if ($sDate > $eDate) {
961
            $startDate = $eDate;
962
            $endDate = $sDate;
963
        }
964
965
        // Execute function
966
        $startDoW = 6 - self::DAYOFWEEK($startDate, 2);
967
        if ($startDoW < 0) {
968
            $startDoW = 0;
969
        }
970
        $endDoW = self::DAYOFWEEK($endDate, 2);
971
        if ($endDoW >= 6) {
972
            $endDoW = 0;
973
        }
974
975
        $wholeWeekDays = floor(($endDate - $startDate) / 7) * 5;
976
        $partWeekDays = $endDoW + $startDoW;
977
        if ($partWeekDays > 5) {
978
            $partWeekDays -= 5;
979
        }
980
981
        //    Test any extra holiday parameters
982
        $holidayCountedArray = array();
983
        foreach ($dateArgs as $holidayDate) {
984
            if (is_string($holidayDate = self::getDateValue($holidayDate))) {
985
                return Functions::VALUE();
986
            }
987
            if (($holidayDate >= $startDate) && ($holidayDate <= $endDate)) {
988
                if ((self::DAYOFWEEK($holidayDate, 2) < 6) && (!in_array($holidayDate, $holidayCountedArray))) {
989
                    --$partWeekDays;
990
                    $holidayCountedArray[] = $holidayDate;
991
                }
992
            }
993
        }
994
995
        if ($sDate > $eDate) {
996
            return 0 - ($wholeWeekDays + $partWeekDays);
997
        }
998
        return $wholeWeekDays + $partWeekDays;
999
    }
1000
1001
1002
    /**
1003
     * WORKDAY
1004
     *
1005
     * Returns the date that is the indicated number of working days before or after a date (the
1006
     * starting date). Working days exclude weekends and any dates identified as holidays.
1007
     * Use WORKDAY to exclude weekends or holidays when you calculate invoice due dates, expected
1008
     * delivery times, or the number of days of work performed.
1009
     *
1010
     * Excel Function:
1011
     *        WORKDAY(startDate,endDays[,holidays[,holiday[,...]]])
1012
     *
1013
     * @access    public
1014
     * @category Date/Time Functions
1015
     * @param    mixed        $startDate        Excel date serial value (float), PHP date timestamp (integer),
1016
     *                                        PHP DateTime object, or a standard date string
1017
     * @param    integer        $endDays        The number of nonweekend and nonholiday days before or after
1018
     *                                        startDate. A positive value for days yields a future date; a
1019
     *                                        negative value yields a past date.
1020
     * @param    mixed        $holidays,...    Optional series of Excel date serial value (float), PHP date
0 ignored issues
show
Bug introduced by
There is no parameter named $holidays,.... Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

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