Passed
Push — master ( 5dee5a...729c4d )
by
unknown
20:09 queued 09:33
created

Helpers::dateParseSucceeded()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 1
c 0
b 0
f 0
nc 1
nop 1
dl 0
loc 3
ccs 2
cts 2
cp 1
crap 1
rs 10
1
<?php
2
3
namespace PhpOffice\PhpSpreadsheet\Calculation\DateTimeExcel;
4
5
use DateTime;
6
use PhpOffice\PhpSpreadsheet\Calculation\Exception;
7
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
8
use PhpOffice\PhpSpreadsheet\Calculation\Information\ExcelError;
9
use PhpOffice\PhpSpreadsheet\Shared\Date as SharedDateHelper;
10
11
class Helpers
12
{
13
    /**
14
     * Identify if a year is a leap year or not.
15
     *
16
     * @param int|string $year The year to test
17
     *
18
     * @return bool TRUE if the year is a leap year, otherwise FALSE
19
     */
20 186
    public static function isLeapYear(int|string $year): bool
21
    {
22 186
        $year = (int) $year;
23
24 186
        return (($year % 4) === 0) && (($year % 100) !== 0) || (($year % 400) === 0);
25
    }
26
27
    /**
28
     * getDateValue.
29
     *
30
     * @return float Excel date/time serial value
31
     */
32 2383
    public static function getDateValue(mixed $dateValue, bool $allowBool = true): float
33
    {
34 2383
        if (is_object($dateValue)) {
35 3
            $retval = SharedDateHelper::PHPToExcel($dateValue);
36 3
            if (is_bool($retval)) {
37
                throw new Exception(ExcelError::VALUE());
38
            }
39
40 3
            return $retval;
41
        }
42
43 2380
        self::nullFalseTrueToNumber($dateValue, $allowBool);
44 2380
        if (!is_numeric($dateValue)) {
45 2077
            $saveReturnDateType = Functions::getReturnDateType();
46 2077
            Functions::setReturnDateType(Functions::RETURNDATE_EXCEL);
47 2077
            if (is_string($dateValue)) {
48 2071
                $dateValue = DateValue::fromString($dateValue);
49
            }
50 2077
            Functions::setReturnDateType($saveReturnDateType);
51 2077
            if (!is_numeric($dateValue)) {
52 138
                throw new Exception(ExcelError::VALUE());
53
            }
54
        }
55 2284
        if ($dateValue < 0 && Functions::getCompatibilityMode() !== Functions::COMPATIBILITY_OPENOFFICE) {
56 20
            throw new Exception(ExcelError::NAN());
57
        }
58
59 2264
        return (float) $dateValue;
60
    }
61
62
    /**
63
     * getTimeValue.
64
     *
65
     * @return float|string Excel date/time serial value, or string if error
66
     */
67 54
    public static function getTimeValue(string $timeValue): string|float
68
    {
69 54
        $saveReturnDateType = Functions::getReturnDateType();
70 54
        Functions::setReturnDateType(Functions::RETURNDATE_EXCEL);
71
        /** @var float|string $timeValue */
72 54
        $timeValue = TimeValue::fromString($timeValue);
73 54
        Functions::setReturnDateType($saveReturnDateType);
74
75 54
        return $timeValue;
76
    }
77
78
    /**
79
     * Adjust date by given months.
80
     *
81
     * @param float|int $dateValue date to be adjusted
82
     */
83 114
    public static function adjustDateByMonths($dateValue = 0, float $adjustmentMonths = 0): DateTime
84
    {
85
        // Execute function
86 114
        $PHPDateObject = SharedDateHelper::excelToDateTimeObject($dateValue);
87 114
        $oMonth = (int) $PHPDateObject->format('m');
88 114
        $oYear = (int) $PHPDateObject->format('Y');
89
90 114
        $adjustmentMonthsString = (string) $adjustmentMonths;
91 114
        if ($adjustmentMonths > 0) {
92 68
            $adjustmentMonthsString = '+' . $adjustmentMonths;
93
        }
94 114
        if ($adjustmentMonths != 0) {
95 97
            $PHPDateObject->modify($adjustmentMonthsString . ' months');
96
        }
97 114
        $nMonth = (int) $PHPDateObject->format('m');
98 114
        $nYear = (int) $PHPDateObject->format('Y');
99
100 114
        $monthDiff = ($nMonth - $oMonth) + (($nYear - $oYear) * 12);
101 114
        if ($monthDiff != $adjustmentMonths) {
102 16
            $adjustDays = (int) $PHPDateObject->format('d');
103 16
            $adjustDaysString = '-' . $adjustDays . ' days';
104 16
            $PHPDateObject->modify($adjustDaysString);
105
        }
106
107 114
        return $PHPDateObject;
108
    }
109
110
    /**
111
     * Help reduce perceived complexity of some tests.
112
     */
113 2231
    public static function replaceIfEmpty(mixed &$value, mixed $altValue): void
114
    {
115 2231
        $value = $value ?: $altValue;
116
    }
117
118
    /**
119
     * Adjust year in ambiguous situations.
120
     */
121 1639
    public static function adjustYear(string $testVal1, string $testVal2, string &$testVal3): void
122
    {
123 1639
        if (!is_numeric($testVal1) || $testVal1 < 31) {
124 133
            if (!is_numeric($testVal2) || $testVal2 < 12) {
125 84
                if (is_numeric($testVal3) && $testVal3 < 12) {
126 4
                    $testVal3 = (string) ($testVal3 + 2000);
127
                }
128
            }
129
        }
130
    }
131
132
    /**
133
     * Return result in one of three formats.
134
     */
135 2237
    public static function returnIn3FormatsArray(array $dateArray, bool $noFrac = false): DateTime|float|int
136
    {
137 2237
        $retType = Functions::getReturnDateType();
138 2237
        if ($retType === Functions::RETURNDATE_PHP_DATETIME_OBJECT) {
139 1
            return new DateTime(
140 1
                $dateArray['year']
141 1
                . '-' . $dateArray['month']
142 1
                . '-' . $dateArray['day']
143 1
                . ' ' . $dateArray['hour']
144 1
                . ':' . $dateArray['minute']
145 1
                . ':' . $dateArray['second']
146 1
            );
147
        }
148 2236
        $excelDateValue
149 2236
            = SharedDateHelper::formattedPHPToExcel(
150 2236
                $dateArray['year'],
151 2236
                $dateArray['month'],
152 2236
                $dateArray['day'],
153 2236
                $dateArray['hour'],
154 2236
                $dateArray['minute'],
155 2236
                $dateArray['second']
156 2236
            );
157 2236
        if ($retType === Functions::RETURNDATE_EXCEL) {
158 2235
            return $noFrac ? floor($excelDateValue) : $excelDateValue;
159
        }
160
        // RETURNDATE_UNIX_TIMESTAMP)
161
162 1
        return SharedDateHelper::excelToTimestamp($excelDateValue);
163
    }
164
165
    /**
166
     * Return result in one of three formats.
167
     */
168 378
    public static function returnIn3FormatsFloat(float $excelDateValue): float|int|DateTime
169
    {
170 378
        $retType = Functions::getReturnDateType();
171 378
        if ($retType === Functions::RETURNDATE_EXCEL) {
172 376
            return $excelDateValue;
173
        }
174 2
        if ($retType === Functions::RETURNDATE_UNIX_TIMESTAMP) {
175 1
            return SharedDateHelper::excelToTimestamp($excelDateValue);
176
        }
177
        // RETURNDATE_PHP_DATETIME_OBJECT
178
179 1
        return SharedDateHelper::excelToDateTimeObject($excelDateValue);
180
    }
181
182
    /**
183
     * Return result in one of three formats.
184
     */
185 114
    public static function returnIn3FormatsObject(DateTime $PHPDateObject): DateTime|float|int
186
    {
187 114
        $retType = Functions::getReturnDateType();
188 114
        if ($retType === Functions::RETURNDATE_PHP_DATETIME_OBJECT) {
189 2
            return $PHPDateObject;
190
        }
191 112
        if ($retType === Functions::RETURNDATE_EXCEL) {
192 110
            return (float) SharedDateHelper::PHPToExcel($PHPDateObject);
193
        }
194
        // RETURNDATE_UNIX_TIMESTAMP
195 2
        $stamp = SharedDateHelper::PHPToExcel($PHPDateObject);
196 2
        $stamp = is_bool($stamp) ? ((int) $stamp) : $stamp;
197
198 2
        return SharedDateHelper::excelToTimestamp($stamp);
199
    }
200
201 2527
    private static function baseDate(): int
202
    {
203 2527
        if (Functions::getCompatibilityMode() === Functions::COMPATIBILITY_OPENOFFICE) {
204 26
            return 0;
205
        }
206 2501
        if (SharedDateHelper::getExcelCalendar() === SharedDateHelper::CALENDAR_MAC_1904) {
207 102
            return 0;
208
        }
209
210 2399
        return 1;
211
    }
212
213
    /**
214
     * Many functions accept null/false/true argument treated as 0/0/1.
215
     */
216 2527
    public static function nullFalseTrueToNumber(mixed &$number, bool $allowBool = true): void
217
    {
218 2527
        $number = Functions::flattenSingleValue($number);
219 2527
        $nullVal = self::baseDate();
220 2527
        if ($number === null) {
221 104
            $number = $nullVal;
222 2526
        } elseif ($allowBool && is_bool($number)) {
223 42
            $number = $nullVal + (int) $number;
224
        }
225
    }
226
227
    /**
228
     * Many functions accept null argument treated as 0.
229
     */
230 783
    public static function validateNumericNull(mixed $number): int|float
231
    {
232 783
        $number = Functions::flattenSingleValue($number);
233 783
        if ($number === null) {
234 2
            return 0;
235
        }
236 781
        if (is_int($number)) {
237 755
            return $number;
238
        }
239 26
        if (is_numeric($number)) {
240 5
            return (float) $number;
241
        }
242
243 21
        throw new Exception(ExcelError::VALUE());
244
    }
245
246
    /**
247
     * Many functions accept null/false/true argument treated as 0/0/1.
248
     *
249
     * @phpstan-assert float $number
250
     */
251 152
    public static function validateNotNegative(mixed $number): float
252
    {
253 152
        if (!is_numeric($number)) {
254 18
            throw new Exception(ExcelError::VALUE());
255
        }
256 134
        if ($number >= 0) {
257 125
            return (float) $number;
258
        }
259
260 9
        throw new Exception(ExcelError::NAN());
261
    }
262
263 621
    public static function silly1900(DateTime $PHPDateObject, string $mod = '-1 day'): void
264
    {
265 621
        $isoDate = $PHPDateObject->format('c');
266 621
        if ($isoDate < '1900-03-01') {
267 86
            $PHPDateObject->modify($mod);
268
        }
269
    }
270
271 2418
    public static function dateParse(string $string): array
272
    {
273 2418
        return self::forceArray(date_parse($string));
274
    }
275
276 2418
    public static function dateParseSucceeded(array $dateArray): bool
277
    {
278 2418
        return $dateArray['error_count'] === 0;
279
    }
280
281
    /**
282
     * Despite documentation, date_parse probably never returns false.
283
     * Just in case, this routine helps guarantee it.
284
     *
285
     * @param array|false $dateArray
286
     */
287 2418
    private static function forceArray(array|bool $dateArray): array
288
    {
289 2418
        return is_array($dateArray) ? $dateArray : ['error_count' => 1];
290
    }
291
292 538
    public static function floatOrInt(mixed $value): float|int
293
    {
294 538
        $result = Functions::scalar($value);
295
296 538
        return is_numeric($result) ? ($result + 0) : 0;
297
    }
298
}
299