briannesbitt / Carbon
1
<?php
2

3
/**
4
 * This file is part of the Carbon package.
5
 *
6
 * (c) Brian Nesbitt <brian@nesbot.com>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
namespace Carbon\Traits;
12

13
use Carbon\CarbonInterface;
14
use DateTimeInterface;
15
use Throwable;
16

17
/**
18
 * Trait Options.
19
 *
20
 * Embed base methods to change settings of Carbon classes.
21
 *
22
 * Depends on the following methods:
23
 *
24
 * @method \Carbon\Carbon|\Carbon\CarbonImmutable shiftTimezone($timezone) Set the timezone
25
 */
26
trait Options
27
{
28
    use Localization;
29

30
    /**
31
     * Customizable PHP_INT_SIZE override.
32
     *
33
     * @var int
34
     */
35
    public static $PHPIntSize = PHP_INT_SIZE;
36

37
    /**
38
     * First day of week.
39
     *
40
     * @var int|string
41
     */
42
    protected static $weekStartsAt = CarbonInterface::MONDAY;
43

44
    /**
45
     * Last day of week.
46
     *
47
     * @var int|string
48
     */
49
    protected static $weekEndsAt = CarbonInterface::SUNDAY;
50

51
    /**
52
     * Days of weekend.
53
     *
54
     * @var array
55
     */
56
    protected static $weekendDays = [
57
        CarbonInterface::SATURDAY,
58
        CarbonInterface::SUNDAY,
59
    ];
60

61
    /**
62
     * Format regex patterns.
63
     *
64
     * @var array<string, string>
65
     */
66
    protected static $regexFormats = [
67
        'd' => '(3[01]|[12][0-9]|0[1-9])',
68
        'D' => '(Sun|Mon|Tue|Wed|Thu|Fri|Sat)',
69
        'j' => '([123][0-9]|[1-9])',
70
        'l' => '([a-zA-Z]{2,})',
71
        'N' => '([1-7])',
72
        'S' => '(st|nd|rd|th)',
73
        'w' => '([0-6])',
74
        'z' => '(36[0-5]|3[0-5][0-9]|[12][0-9]{2}|[1-9]?[0-9])',
75
        'W' => '(5[012]|[1-4][0-9]|0?[1-9])',
76
        'F' => '([a-zA-Z]{2,})',
77
        'm' => '(1[012]|0[1-9])',
78
        'M' => '([a-zA-Z]{3})',
79
        'n' => '(1[012]|[1-9])',
80
        't' => '(2[89]|3[01])',
81
        'L' => '(0|1)',
82
        'o' => '([1-9][0-9]{0,4})',
83
        'Y' => '([1-9]?[0-9]{4})',
84
        'y' => '([0-9]{2})',
85
        'a' => '(am|pm)',
86
        'A' => '(AM|PM)',
87
        'B' => '([0-9]{3})',
88
        'g' => '(1[012]|[1-9])',
89
        'G' => '(2[0-3]|1?[0-9])',
90
        'h' => '(1[012]|0[1-9])',
91
        'H' => '(2[0-3]|[01][0-9])',
92
        'i' => '([0-5][0-9])',
93
        's' => '([0-5][0-9])',
94
        'u' => '([0-9]{1,6})',
95
        'v' => '([0-9]{1,3})',
96
        'e' => '([a-zA-Z]{1,5})|([a-zA-Z]*\\/[a-zA-Z]*)',
97
        'I' => '(0|1)',
98
        'O' => '([+-](1[012]|0[0-9])[0134][05])',
99
        'P' => '([+-](1[012]|0[0-9]):[0134][05])',
100
        'p' => '(Z|[+-](1[012]|0[0-9]):[0134][05])',
101
        'T' => '([a-zA-Z]{1,5})',
102
        'Z' => '(-?[1-5]?[0-9]{1,4})',
103
        'U' => '([0-9]*)',
104

105
        // The formats below are combinations of the above formats.
106
        'c' => '(([1-9]?[0-9]{4})-(1[012]|0[1-9])-(3[01]|[12][0-9]|0[1-9])T(2[0-3]|[01][0-9]):([0-5][0-9]):([0-5][0-9])[+-](1[012]|0[0-9]):([0134][05]))', // Y-m-dTH:i:sP
107
        'r' => '(([a-zA-Z]{3}), ([123][0-9]|0[1-9]) ([a-zA-Z]{3}) ([1-9]?[0-9]{4}) (2[0-3]|[01][0-9]):([0-5][0-9]):([0-5][0-9]) [+-](1[012]|0[0-9])([0134][05]))', // D, d M Y H:i:s O
108
    ];
109

110
    /**
111
     * Format modifiers (such as available in createFromFormat) regex patterns.
112
     *
113
     * @var array
114
     */
115
    protected static $regexFormatModifiers = [
116
        '*' => '.+',
117
        ' ' => '[   ]',
118
        '#' => '[;:\\/.,()-]',
119
        '?' => '([^a]|[a])',
120
        '!' => '',
121
        '|' => '',
122
        '+' => '',
123
    ];
124

125
    /**
126
     * Indicates if months should be calculated with overflow.
127
     * Global setting.
128
     *
129
     * @var bool
130
     */
131
    protected static $monthsOverflow = true;
132

133
    /**
134
     * Indicates if years should be calculated with overflow.
135
     * Global setting.
136
     *
137
     * @var bool
138
     */
139
    protected static $yearsOverflow = true;
140

141
    /**
142
     * Indicates if the strict mode is in use.
143
     * Global setting.
144
     *
145
     * @var bool
146
     */
147
    protected static $strictModeEnabled = true;
148

149
    /**
150
     * Function to call instead of format.
151
     *
152
     * @var string|callable|null
153
     */
154
    protected static $formatFunction = null;
155

156
    /**
157
     * Function to call instead of createFromFormat.
158
     *
159
     * @var string|callable|null
160
     */
161
    protected static $createFromFormatFunction = null;
162

163
    /**
164
     * Function to call instead of parse.
165
     *
166
     * @var string|callable|null
167
     */
168
    protected static $parseFunction = null;
169

170
    /**
171
     * Indicates if months should be calculated with overflow.
172
     * Specific setting.
173
     *
174
     * @var bool|null
175
     */
176
    protected $localMonthsOverflow = null;
177

178
    /**
179
     * Indicates if years should be calculated with overflow.
180
     * Specific setting.
181
     *
182
     * @var bool|null
183
     */
184
    protected $localYearsOverflow = null;
185

186
    /**
187
     * Indicates if the strict mode is in use.
188
     * Specific setting.
189
     *
190
     * @var bool|null
191
     */
192
    protected $localStrictModeEnabled = null;
193

194
    /**
195
     * Options for diffForHumans and forHumans methods.
196
     *
197
     * @var bool|null
198
     */
199
    protected $localHumanDiffOptions = null;
200

201
    /**
202
     * Format to use on string cast.
203
     *
204
     * @var string|null
205
     */
206
    protected $localToStringFormat = null;
207

208
    /**
209
     * Format to use on JSON serialization.
210
     *
211
     * @var string|null
212
     */
213
    protected $localSerializer = null;
214

215
    /**
216
     * Instance-specific macros.
217
     *
218
     * @var array|null
219
     */
220
    protected $localMacros = null;
221

222
    /**
223
     * Instance-specific generic macros.
224
     *
225
     * @var array|null
226
     */
227
    protected $localGenericMacros = null;
228

229
    /**
230
     * Function to call instead of format.
231
     *
232
     * @var string|callable|null
233
     */
234
    protected $localFormatFunction = null;
235

236
    /**
237
     * @deprecated To avoid conflict between different third-party libraries, static setters should not be used.
238
     *             You should rather use the ->settings() method.
239
     * @see settings
240
     *
241
     * Enable the strict mode (or disable with passing false).
242
     *
243
     * @param bool $strictModeEnabled
244
     */
245 1
    public static function useStrictMode($strictModeEnabled = true)
246
    {
247 1
        static::$strictModeEnabled = $strictModeEnabled;
248
    }
249

250
    /**
251
     * Returns true if the strict mode is globally in use, false else.
252
     * (It can be overridden in specific instances.)
253
     *
254
     * @return bool
255
     */
256 1
    public static function isStrictModeEnabled()
257
    {
258 1
        return static::$strictModeEnabled;
259
    }
260

261
    /**
262
     * @deprecated To avoid conflict between different third-party libraries, static setters should not be used.
263
     *             You should rather use the ->settings() method.
264
     *             Or you can use method variants: addMonthsWithOverflow/addMonthsNoOverflow, same variants
265
     *             are available for quarters, years, decade, centuries, millennia (singular and plural forms).
266
     * @see settings
267
     *
268
     * Indicates if months should be calculated with overflow.
269
     *
270
     * @param bool $monthsOverflow
271
     *
272
     * @return void
273
     */
274 1
    public static function useMonthsOverflow($monthsOverflow = true)
275
    {
276 1
        static::$monthsOverflow = $monthsOverflow;
277
    }
278

279
    /**
280
     * @deprecated To avoid conflict between different third-party libraries, static setters should not be used.
281
     *             You should rather use the ->settings() method.
282
     *             Or you can use method variants: addMonthsWithOverflow/addMonthsNoOverflow, same variants
283
     *             are available for quarters, years, decade, centuries, millennia (singular and plural forms).
284
     * @see settings
285
     *
286
     * Reset the month overflow behavior.
287
     *
288
     * @return void
289
     */
290 1
    public static function resetMonthsOverflow()
291
    {
292 1
        static::$monthsOverflow = true;
293
    }
294

295
    /**
296
     * Get the month overflow global behavior (can be overridden in specific instances).
297
     *
298
     * @return bool
299
     */
300 1
    public static function shouldOverflowMonths()
301
    {
302 1
        return static::$monthsOverflow;
303
    }
304

305
    /**
306
     * @deprecated To avoid conflict between different third-party libraries, static setters should not be used.
307
     *             You should rather use the ->settings() method.
308
     *             Or you can use method variants: addYearsWithOverflow/addYearsNoOverflow, same variants
309
     *             are available for quarters, years, decade, centuries, millennia (singular and plural forms).
310
     * @see settings
311
     *
312
     * Indicates if years should be calculated with overflow.
313
     *
314
     * @param bool $yearsOverflow
315
     *
316
     * @return void
317
     */
318 1
    public static function useYearsOverflow($yearsOverflow = true)
319
    {
320 1
        static::$yearsOverflow = $yearsOverflow;
321
    }
322

323
    /**
324
     * @deprecated To avoid conflict between different third-party libraries, static setters should not be used.
325
     *             You should rather use the ->settings() method.
326
     *             Or you can use method variants: addYearsWithOverflow/addYearsNoOverflow, same variants
327
     *             are available for quarters, years, decade, centuries, millennia (singular and plural forms).
328
     * @see settings
329
     *
330
     * Reset the month overflow behavior.
331
     *
332
     * @return void
333
     */
334 1
    public static function resetYearsOverflow()
335
    {
336 1
        static::$yearsOverflow = true;
337
    }
338

339
    /**
340
     * Get the month overflow global behavior (can be overridden in specific instances).
341
     *
342
     * @return bool
343
     */
344 1
    public static function shouldOverflowYears()
345
    {
346 1
        return static::$yearsOverflow;
347
    }
348

349
    /**
350
     * Set specific options.
351
     *  - strictMode: true|false|null
352
     *  - monthOverflow: true|false|null
353
     *  - yearOverflow: true|false|null
354
     *  - humanDiffOptions: int|null
355
     *  - toStringFormat: string|Closure|null
356
     *  - toJsonFormat: string|Closure|null
357
     *  - locale: string|null
358
     *  - timezone: \DateTimeZone|string|int|null
359
     *  - macros: array|null
360
     *  - genericMacros: array|null
361
     *
362
     * @param array $settings
363
     *
364
     * @return $this|static
365
     */
366 1
    public function settings(array $settings)
367
    {
368 1
        $this->localStrictModeEnabled = $settings['strictMode'] ?? null;
369 1
        $this->localMonthsOverflow = $settings['monthOverflow'] ?? null;
370 1
        $this->localYearsOverflow = $settings['yearOverflow'] ?? null;
371 1
        $this->localHumanDiffOptions = $settings['humanDiffOptions'] ?? null;
372 1
        $this->localToStringFormat = $settings['toStringFormat'] ?? null;
373 1
        $this->localSerializer = $settings['toJsonFormat'] ?? null;
374 1
        $this->localMacros = $settings['macros'] ?? null;
375 1
        $this->localGenericMacros = $settings['genericMacros'] ?? null;
376 1
        $this->localFormatFunction = $settings['formatFunction'] ?? null;
377

378 1
        if (isset($settings['locale'])) {
379 1
            $locales = $settings['locale'];
380

381 1
            if (!\is_array($locales)) {
382 1
                $locales = [$locales];
383
            }
384

385 1
            $this->locale(...$locales);
386
        }
387

388 1
        if (isset($settings['timezone'])) {
389 1
            return $this->shiftTimezone($settings['timezone']);
390
        }
391

392 1
        return $this;
393
    }
394

395
    /**
396
     * Returns current local settings.
397
     *
398
     * @return array
399
     */
400 1
    public function getSettings()
401
    {
402 1
        $settings = [];
403
        $map = [
404 1
            'localStrictModeEnabled' => 'strictMode',
405
            'localMonthsOverflow' => 'monthOverflow',
406
            'localYearsOverflow' => 'yearOverflow',
407
            'localHumanDiffOptions' => 'humanDiffOptions',
408
            'localToStringFormat' => 'toStringFormat',
409
            'localSerializer' => 'toJsonFormat',
410
            'localMacros' => 'macros',
411
            'localGenericMacros' => 'genericMacros',
412
            'locale' => 'locale',
413
            'tzName' => 'timezone',
414
            'localFormatFunction' => 'formatFunction',
415
        ];
416

417 1
        foreach ($map as $property => $key) {
418 1
            $value = $this->$property ?? null;
419

420 1
            if ($value !== null) {
421 1
                $settings[$key] = $value;
422
            }
423
        }
424

425 1
        return $settings;
426
    }
427

428
    /**
429
     * Show truthy properties on var_dump().
430
     *
431
     * @return array
432
     */
433 1
    public function __debugInfo()
434
    {
435
        $infos = array_filter(get_object_vars($this), function ($var) {
436 1
            return $var;
437 1
        });
438

439 1
        foreach (['dumpProperties', 'constructedObjectId'] as $property) {
440 1
            if (isset($infos[$property])) {
441 1
                unset($infos[$property]);
442
            }
443
        }
444

445 1
        $this->addExtraDebugInfos($infos);
446

447 1
        return $infos;
448
    }
449

450 1
    protected function addExtraDebugInfos(&$infos): void
451
    {
452 1
        if ($this instanceof CarbonInterface || $this instanceof DateTimeInterface) {
453
            try {
454 1
                if (!isset($infos['date'])) {
455 1
                    $infos['date'] = $this->format(CarbonInterface::MOCK_DATETIME_FORMAT);
456
                }
457

458 1
                if (!isset($infos['timezone'])) {
459 1
                    $infos['timezone'] = $this->tzName;
460
                }
461 1
            } catch (Throwable $exception) {
462
                // noop
463
            }
464
        }
465
    }
466
}

Read our documentation on viewing source code .

Loading