Passed
Push — master ( d01575...9b3f20 )
by
unknown
20:24 queued 13s
created

NumberFormat::setShortDateFormat()   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
eloc 1
dl 0
loc 3
ccs 2
cts 2
cp 1
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 1
crap 1
1
<?php
2
3
namespace PhpOffice\PhpSpreadsheet\Style;
4
5
class NumberFormat extends Supervisor
6
{
7
    // Pre-defined formats
8
    const FORMAT_GENERAL = 'General';
9
10
    const FORMAT_TEXT = '@';
11
12
    const FORMAT_NUMBER = '0';
13
    const FORMAT_NUMBER_0 = '0.0';
14
    const FORMAT_NUMBER_00 = '0.00';
15
    const FORMAT_NUMBER_COMMA_SEPARATED1 = '#,##0.00';
16
    const FORMAT_NUMBER_COMMA_SEPARATED2 = '#,##0.00_-';
17
18
    const FORMAT_PERCENTAGE = '0%';
19
    const FORMAT_PERCENTAGE_0 = '0.0%';
20
    const FORMAT_PERCENTAGE_00 = '0.00%';
21
22
    const FORMAT_DATE_YYYYMMDD = 'yyyy-mm-dd';
23
    const FORMAT_DATE_DDMMYYYY = 'dd/mm/yyyy';
24
    const FORMAT_DATE_DMYSLASH = 'd/m/yy';
25
    const FORMAT_DATE_DMYMINUS = 'd-m-yy';
26
    const FORMAT_DATE_DMMINUS = 'd-m';
27
    const FORMAT_DATE_MYMINUS = 'm-yy';
28
    const FORMAT_DATE_XLSX14 = 'mm-dd-yy';
29
    const FORMAT_DATE_XLSX14_ACTUAL = 'm/d/yyyy';
30
    const FORMAT_DATE_XLSX15 = 'd-mmm-yy';
31
    const FORMAT_DATE_XLSX16 = 'd-mmm';
32
    const FORMAT_DATE_XLSX17 = 'mmm-yy';
33
    const FORMAT_DATE_XLSX22 = 'm/d/yy h:mm';
34
    const FORMAT_DATE_XLSX22_ACTUAL = 'm/d/yyyy h:mm';
35
    const FORMAT_DATE_DATETIME = 'd/m/yy h:mm';
36
    const FORMAT_DATE_TIME1 = 'h:mm AM/PM';
37
    const FORMAT_DATE_TIME2 = 'h:mm:ss AM/PM';
38
    const FORMAT_DATE_TIME3 = 'h:mm';
39
    const FORMAT_DATE_TIME4 = 'h:mm:ss';
40
    const FORMAT_DATE_TIME5 = 'mm:ss';
41
    const FORMAT_DATE_TIME6 = 'h:mm:ss';
42
    const FORMAT_DATE_TIME7 = 'i:s.S';
43
    const FORMAT_DATE_TIME8 = 'h:mm:ss;@';
44
    const FORMAT_DATE_YYYYMMDDSLASH = 'yyyy/mm/dd;@';
45
    const FORMAT_DATE_LONG_DATE = 'dddd, mmmm d, yyyy';
46
47
    const DATE_TIME_OR_DATETIME_ARRAY = [
48
        self::FORMAT_DATE_YYYYMMDD,
49
        self::FORMAT_DATE_DDMMYYYY,
50
        self::FORMAT_DATE_DMYSLASH,
51
        self::FORMAT_DATE_DMYMINUS,
52
        self::FORMAT_DATE_DMMINUS,
53
        self::FORMAT_DATE_MYMINUS,
54
        self::FORMAT_DATE_XLSX14,
55
        self::FORMAT_DATE_XLSX14_ACTUAL,
56
        self::FORMAT_DATE_XLSX15,
57
        self::FORMAT_DATE_XLSX16,
58
        self::FORMAT_DATE_XLSX17,
59
        self::FORMAT_DATE_XLSX22,
60
        self::FORMAT_DATE_XLSX22_ACTUAL,
61
        self::FORMAT_DATE_DATETIME,
62
        self::FORMAT_DATE_TIME1,
63
        self::FORMAT_DATE_TIME2,
64
        self::FORMAT_DATE_TIME3,
65
        self::FORMAT_DATE_TIME4,
66
        self::FORMAT_DATE_TIME5,
67
        self::FORMAT_DATE_TIME6,
68
        self::FORMAT_DATE_TIME7,
69
        self::FORMAT_DATE_TIME8,
70
        self::FORMAT_DATE_YYYYMMDDSLASH,
71
        self::FORMAT_DATE_LONG_DATE,
72
    ];
73
    const TIME_OR_DATETIME_ARRAY = [
74
        self::FORMAT_DATE_XLSX22,
75
        self::FORMAT_DATE_DATETIME,
76
        self::FORMAT_DATE_TIME1,
77
        self::FORMAT_DATE_TIME2,
78
        self::FORMAT_DATE_TIME3,
79
        self::FORMAT_DATE_TIME4,
80
        self::FORMAT_DATE_TIME5,
81
        self::FORMAT_DATE_TIME6,
82
        self::FORMAT_DATE_TIME7,
83
        self::FORMAT_DATE_TIME8,
84
    ];
85
86
    const FORMAT_CURRENCY_USD_INTEGER = '$#,##0_-';
87
    const FORMAT_CURRENCY_USD = '$#,##0.00_-';
88
    const FORMAT_CURRENCY_EUR_INTEGER = '#,##0_-[$€]';
89
    const FORMAT_CURRENCY_EUR = '#,##0.00_-[$€]';
90
    const FORMAT_ACCOUNTING_USD = '_("$"* #,##0.00_);_("$"* \(#,##0.00\);_("$"* "-"??_);_(@_)';
91
    const FORMAT_ACCOUNTING_EUR = '_("€"* #,##0.00_);_("€"* \(#,##0.00\);_("€"* "-"??_);_(@_)';
92
93
    const SHORT_DATE_INDEX = 14;
94
    const DATE_TIME_INDEX = 22;
95
    const FORMAT_SYSDATE_X = '[$-x-sysdate]';
96
    const FORMAT_SYSDATE_F800 = '[$-F800]';
97
    const FORMAT_SYSTIME_X = '[$-x-systime]';
98
    const FORMAT_SYSTIME_F400 = '[$-F400]';
99
100
    protected static string $shortDateFormat = self::FORMAT_DATE_XLSX14_ACTUAL;
101
102
    protected static string $longDateFormat = self::FORMAT_DATE_LONG_DATE;
103
104
    protected static string $dateTimeFormat = self::FORMAT_DATE_XLSX22_ACTUAL;
105
106
    protected static string $timeFormat = self::FORMAT_DATE_TIME2;
107
108
    /**
109
     * Excel built-in number formats.
110
     */
111
    protected static array $builtInFormats;
112
113
    /**
114
     * Excel built-in number formats (flipped, for faster lookups).
115
     */
116
    protected static array $flippedBuiltInFormats;
117
118
    /**
119
     * Format Code.
120
     */
121
    protected ?string $formatCode = self::FORMAT_GENERAL;
122
123
    /**
124
     * Built-in format Code.
125
     *
126
     * @var false|int
127
     */
128
    protected $builtInFormatCode = 0;
129
130
    /**
131
     * Create a new NumberFormat.
132
     *
133
     * @param bool $isSupervisor Flag indicating if this is a supervisor or not
134
     *                                    Leave this value at default unless you understand exactly what
135
     *                                        its ramifications are
136
     * @param bool $isConditional Flag indicating if this is a conditional style or not
137
     *                                    Leave this value at default unless you understand exactly what
138
     *                                        its ramifications are
139
     */
140 10026
    public function __construct(bool $isSupervisor = false, bool $isConditional = false)
141
    {
142
        // Supervisor?
143 10026
        parent::__construct($isSupervisor);
144
145 10026
        if ($isConditional) {
146 371
            $this->formatCode = null;
147 371
            $this->builtInFormatCode = false;
148
        }
149
    }
150
151
    /**
152
     * Get the shared style component for the currently active cell in currently active sheet.
153
     * Only used for style supervisor.
154
     */
155 108
    public function getSharedComponent(): self
156
    {
157
        /** @var Style $parent */
158 108
        $parent = $this->parent;
159
160 108
        return $parent->getSharedComponent()->getNumberFormat();
161
    }
162
163
    /**
164
     * Build style array from subcomponents.
165
     */
166 632
    public function getStyleArray(array $array): array
167
    {
168 632
        return ['numberFormat' => $array];
169
    }
170
171
    /**
172
     * Apply styles from array.
173
     *
174
     * <code>
175
     * $spreadsheet->getActiveSheet()->getStyle('B2')->getNumberFormat()->applyFromArray(
176
     *     [
177
     *         'formatCode' => NumberFormat::FORMAT_CURRENCY_EUR_SIMPLE
178
     *     ]
179
     * );
180
     * </code>
181
     *
182
     * @param array $styleArray Array containing style information
183
     *
184
     * @return $this
185
     */
186 652
    public function applyFromArray(array $styleArray): static
187
    {
188 652
        if ($this->isSupervisor) {
189 1
            $this->getActiveSheet()->getStyle($this->getSelectedCells())->applyFromArray($this->getStyleArray($styleArray));
190
        } else {
191 652
            if (isset($styleArray['formatCode'])) {
192 652
                $this->setFormatCode($styleArray['formatCode']);
193
            }
194
        }
195
196 652
        return $this;
197
    }
198
199
    /**
200
     * Get Format Code.
201
     */
202 751
    public function getFormatCode(bool $extended = false): ?string
203
    {
204 751
        if ($this->isSupervisor) {
205 108
            return $this->getSharedComponent()->getFormatCode($extended);
206
        }
207 751
        $builtin = $this->getBuiltInFormatCode();
208 751
        if (is_int($builtin)) {
209 353
            if ($extended) {
210 92
                if ($builtin === self::SHORT_DATE_INDEX) {
211 2
                    return self::$shortDateFormat;
212
                }
213 92
                if ($builtin === self::DATE_TIME_INDEX) {
214 2
                    return self::$dateTimeFormat;
215
                }
216
            }
217
218 351
            return self::builtInFormatCode($builtin);
219
        }
220
221 455
        return $extended ? self::convertSystemFormats($this->formatCode) : $this->formatCode;
222
    }
223
224 151
    public static function convertSystemFormats(?string $formatCode): ?string
225
    {
226 151
        if (is_string($formatCode)) {
227 151
            if (stripos($formatCode, self::FORMAT_SYSDATE_F800) !== false || stripos($formatCode, self::FORMAT_SYSDATE_X) !== false) {
228 5
                return self::$longDateFormat;
229
            }
230 149
            if (stripos($formatCode, self::FORMAT_SYSTIME_F400) !== false || stripos($formatCode, self::FORMAT_SYSTIME_X) !== false) {
231 4
                return self::$timeFormat;
232
            }
233
        }
234
235 145
        return $formatCode;
236
    }
237
238
    /**
239
     * Set Format Code.
240
     *
241
     * @param string $formatCode see self::FORMAT_*
242
     *
243
     * @return $this
244
     */
245 1327
    public function setFormatCode(string $formatCode): static
246
    {
247 1327
        if ($formatCode == '') {
248 10
            $formatCode = self::FORMAT_GENERAL;
249
        }
250 1327
        if ($this->isSupervisor) {
251 631
            $styleArray = $this->getStyleArray(['formatCode' => $formatCode]);
252 631
            $this->getActiveSheet()->getStyle($this->getSelectedCells())->applyFromArray($styleArray);
253
        } else {
254 1317
            $this->formatCode = $formatCode;
255 1317
            $this->builtInFormatCode = self::builtInFormatCodeIndex($formatCode);
256
        }
257
258 1317
        return $this;
259
    }
260
261
    /**
262
     * Get Built-In Format Code.
263
     *
264
     * @return false|int
265
     */
266 1032
    public function getBuiltInFormatCode()
267
    {
268 1032
        if ($this->isSupervisor) {
269 1
            return $this->getSharedComponent()->getBuiltInFormatCode();
270
        }
271
272 1032
        return $this->builtInFormatCode;
273
    }
274
275
    /**
276
     * Set Built-In Format Code.
277
     *
278
     * @param int $formatCodeIndex Id of the built-in format code to use
279
     *
280
     * @return $this
281
     */
282 3
    public function setBuiltInFormatCode(int $formatCodeIndex): static
283
    {
284 3
        if ($this->isSupervisor) {
285 3
            $styleArray = $this->getStyleArray(['formatCode' => self::builtInFormatCode($formatCodeIndex)]);
286 3
            $this->getActiveSheet()->getStyle($this->getSelectedCells())->applyFromArray($styleArray);
287
        } else {
288 1
            $this->builtInFormatCode = $formatCodeIndex;
289 1
            $this->formatCode = self::builtInFormatCode($formatCodeIndex);
290
        }
291
292 3
        return $this;
293
    }
294
295
    /**
296
     * Fill built-in format codes.
297
     */
298 1476
    private static function fillBuiltInFormatCodes(): void
299
    {
300
        //  [MS-OI29500: Microsoft Office Implementation Information for ISO/IEC-29500 Standard Compliance]
301
        //  18.8.30. numFmt (Number Format)
302
        //
303
        //  The ECMA standard defines built-in format IDs
304
        //      14: "mm-dd-yy"
305
        //      22: "m/d/yy h:mm"
306
        //      37: "#,##0 ;(#,##0)"
307
        //      38: "#,##0 ;[Red](#,##0)"
308
        //      39: "#,##0.00;(#,##0.00)"
309
        //      40: "#,##0.00;[Red](#,##0.00)"
310
        //      47: "mmss.0"
311
        //      KOR fmt 55: "yyyy-mm-dd"
312
        //  Excel defines built-in format IDs
313
        //      14: "m/d/yyyy"
314
        //      22: "m/d/yyyy h:mm"
315
        //      37: "#,##0_);(#,##0)"
316
        //      38: "#,##0_);[Red](#,##0)"
317
        //      39: "#,##0.00_);(#,##0.00)"
318
        //      40: "#,##0.00_);[Red](#,##0.00)"
319
        //      47: "mm:ss.0"
320
        //      KOR fmt 55: "yyyy/mm/dd"
321
322
        // Built-in format codes
323 1476
        if (empty(self::$builtInFormats)) {
324 156
            self::$builtInFormats = [];
325
326
            // General
327 156
            self::$builtInFormats[0] = self::FORMAT_GENERAL;
328 156
            self::$builtInFormats[1] = '0';
329 156
            self::$builtInFormats[2] = '0.00';
330 156
            self::$builtInFormats[3] = '#,##0';
331 156
            self::$builtInFormats[4] = '#,##0.00';
332
333 156
            self::$builtInFormats[9] = '0%';
334 156
            self::$builtInFormats[10] = '0.00%';
335 156
            self::$builtInFormats[11] = '0.00E+00';
336 156
            self::$builtInFormats[12] = '# ?/?';
337 156
            self::$builtInFormats[13] = '# ??/??';
338 156
            self::$builtInFormats[14] = self::FORMAT_DATE_XLSX14_ACTUAL; // Despite ECMA 'mm-dd-yy';
339 156
            self::$builtInFormats[15] = self::FORMAT_DATE_XLSX15;
340 156
            self::$builtInFormats[16] = 'd-mmm';
341 156
            self::$builtInFormats[17] = 'mmm-yy';
342 156
            self::$builtInFormats[18] = 'h:mm AM/PM';
343 156
            self::$builtInFormats[19] = 'h:mm:ss AM/PM';
344 156
            self::$builtInFormats[20] = 'h:mm';
345 156
            self::$builtInFormats[21] = 'h:mm:ss';
346 156
            self::$builtInFormats[22] = self::FORMAT_DATE_XLSX22_ACTUAL; // Despite ECMA 'm/d/yy h:mm';
347
348 156
            self::$builtInFormats[37] = '#,##0_);(#,##0)'; //  Despite ECMA '#,##0 ;(#,##0)';
349 156
            self::$builtInFormats[38] = '#,##0_);[Red](#,##0)'; //  Despite ECMA '#,##0 ;[Red](#,##0)';
350 156
            self::$builtInFormats[39] = '#,##0.00_);(#,##0.00)'; //  Despite ECMA '#,##0.00;(#,##0.00)';
351 156
            self::$builtInFormats[40] = '#,##0.00_);[Red](#,##0.00)'; //  Despite ECMA '#,##0.00;[Red](#,##0.00)';
352
353 156
            self::$builtInFormats[44] = '_("$"* #,##0.00_);_("$"* \(#,##0.00\);_("$"* "-"??_);_(@_)';
354 156
            self::$builtInFormats[45] = 'mm:ss';
355 156
            self::$builtInFormats[46] = '[h]:mm:ss';
356 156
            self::$builtInFormats[47] = 'mm:ss.0'; //  Despite ECMA 'mmss.0';
357 156
            self::$builtInFormats[48] = '##0.0E+0';
358 156
            self::$builtInFormats[49] = '@';
359
360
            // CHT
361 156
            self::$builtInFormats[27] = '[$-404]e/m/d';
362 156
            self::$builtInFormats[30] = 'm/d/yy';
363 156
            self::$builtInFormats[36] = '[$-404]e/m/d';
364 156
            self::$builtInFormats[50] = '[$-404]e/m/d';
365 156
            self::$builtInFormats[57] = '[$-404]e/m/d';
366
367
            // THA
368 156
            self::$builtInFormats[59] = 't0';
369 156
            self::$builtInFormats[60] = 't0.00';
370 156
            self::$builtInFormats[61] = 't#,##0';
371 156
            self::$builtInFormats[62] = 't#,##0.00';
372 156
            self::$builtInFormats[67] = 't0%';
373 156
            self::$builtInFormats[68] = 't0.00%';
374 156
            self::$builtInFormats[69] = 't# ?/?';
375 156
            self::$builtInFormats[70] = 't# ??/??';
376
377
            // JPN
378 156
            self::$builtInFormats[28] = '[$-411]ggge"年"m"月"d"日"';
379 156
            self::$builtInFormats[29] = '[$-411]ggge"年"m"月"d"日"';
380 156
            self::$builtInFormats[31] = 'yyyy"年"m"月"d"日"';
381 156
            self::$builtInFormats[32] = 'h"時"mm"分"';
382 156
            self::$builtInFormats[33] = 'h"時"mm"分"ss"秒"';
383 156
            self::$builtInFormats[34] = 'yyyy"年"m"月"';
384 156
            self::$builtInFormats[35] = 'm"月"d"日"';
385 156
            self::$builtInFormats[51] = '[$-411]ggge"年"m"月"d"日"';
386 156
            self::$builtInFormats[52] = 'yyyy"年"m"月"';
387 156
            self::$builtInFormats[53] = 'm"月"d"日"';
388 156
            self::$builtInFormats[54] = '[$-411]ggge"年"m"月"d"日"';
389 156
            self::$builtInFormats[55] = 'yyyy"年"m"月"';
390 156
            self::$builtInFormats[56] = 'm"月"d"日"';
391 156
            self::$builtInFormats[58] = '[$-411]ggge"年"m"月"d"日"';
392
393
            // Flip array (for faster lookups)
394 156
            self::$flippedBuiltInFormats = array_flip(self::$builtInFormats);
395
        }
396
    }
397
398
    /**
399
     * Get built-in format code.
400
     */
401 983
    public static function builtInFormatCode(int $index): string
402
    {
403
        // Clean parameter
404 983
        $index = (int) $index;
405
406
        // Ensure built-in format codes are available
407 983
        self::fillBuiltInFormatCodes();
408
409
        // Lookup format code
410 983
        if (isset(self::$builtInFormats[$index])) {
411 983
            return self::$builtInFormats[$index];
412
        }
413
414 14
        return '';
415
    }
416
417
    /**
418
     * Get built-in format code index.
419
     *
420
     * @return false|int
421
     */
422 1317
    public static function builtInFormatCodeIndex(string $formatCodeIndex)
423
    {
424
        // Ensure built-in format codes are available
425 1317
        self::fillBuiltInFormatCodes();
426
427
        // Lookup format code
428 1317
        if (array_key_exists($formatCodeIndex, self::$flippedBuiltInFormats)) {
429 921
            return self::$flippedBuiltInFormats[$formatCodeIndex];
430
        }
431
432 737
        return false;
433
    }
434
435
    /**
436
     * Get hash code.
437
     *
438
     * @return string Hash code
439
     */
440 1066
    public function getHashCode(): string
441
    {
442 1066
        if ($this->isSupervisor) {
443 3
            return $this->getSharedComponent()->getHashCode();
444
        }
445
446 1066
        return md5(
447 1066
            $this->formatCode
448 1066
            . $this->builtInFormatCode
449 1066
            . __CLASS__
450 1066
        );
451
    }
452
453
    /**
454
     * Convert a value in a pre-defined format to a PHP string.
455
     *
456
     * @param mixed $value Value to format
457
     * @param string $format Format code: see = self::FORMAT_* for predefined values;
458
     *                          or can be any valid MS Excel custom format string
459
     * @param ?array $callBack Callback function for additional formatting of string
460
     *
461
     * @return string Formatted string
462
     */
463 1140
    public static function toFormattedString(mixed $value, string $format, ?array $callBack = null): string
464
    {
465 1140
        return NumberFormat\Formatter::toFormattedString($value, $format, $callBack);
466
    }
467
468 7
    protected function exportArray1(): array
469
    {
470 7
        $exportedArray = [];
471 7
        $this->exportArray2($exportedArray, 'formatCode', $this->getFormatCode());
472
473 7
        return $exportedArray;
474
    }
475
476 2
    public static function getShortDateFormat(): string
477
    {
478 2
        return self::$shortDateFormat;
479
    }
480
481 2
    public static function setShortDateFormat(string $shortDateFormat): void
482
    {
483 2
        self::$shortDateFormat = $shortDateFormat;
484
    }
485
486 2
    public static function getLongDateFormat(): string
487
    {
488 2
        return self::$longDateFormat;
489
    }
490
491 2
    public static function setLongDateFormat(string $longDateFormat): void
492
    {
493 2
        self::$longDateFormat = $longDateFormat;
494
    }
495
496 2
    public static function getDateTimeFormat(): string
497
    {
498 2
        return self::$dateTimeFormat;
499
    }
500
501 2
    public static function setDateTimeFormat(string $dateTimeFormat): void
502
    {
503 2
        self::$dateTimeFormat = $dateTimeFormat;
504
    }
505
506 2
    public static function getTimeFormat(): string
507
    {
508 2
        return self::$timeFormat;
509
    }
510
511 2
    public static function setTimeFormat(string $timeFormat): void
512
    {
513 2
        self::$timeFormat = $timeFormat;
514
    }
515
}
516