Issues (75)

Security Analysis    no request data  

This project does not seem to handle request data directly as such no vulnerable execution paths were found.

  Cross-Site Scripting
Cross-Site Scripting enables an attacker to inject code into the response of a web-request that is viewed by other users. It can for example be used to bypass access controls, or even to take over other users' accounts.
  File Exposure
File Exposure allows an attacker to gain access to local files that he should not be able to access. These files can for example include database credentials, or other configuration files.
  File Manipulation
File Manipulation enables an attacker to write custom data to files. This potentially leads to injection of arbitrary code on the server.
  Object Injection
Object Injection enables an attacker to inject an object into PHP code, and can lead to arbitrary code execution, file exposure, or file manipulation attacks.
  Code Injection
Code Injection enables an attacker to execute arbitrary code on the server.
  Response Splitting
Response Splitting can be used to send arbitrary responses.
  File Inclusion
File Inclusion enables an attacker to inject custom files into PHP's file loading mechanism, either explicitly passed to include, or for example via PHP's auto-loading mechanism.
  Command Injection
Command Injection enables an attacker to inject a shell command that is execute with the privileges of the web-server. This can be used to expose sensitive data, or gain access of your server.
  SQL Injection
SQL Injection enables an attacker to execute arbitrary SQL code on your database server gaining access to user data, or manipulating user data.
  XPath Injection
XPath Injection enables an attacker to modify the parts of XML document that are read. If that XML document is for example used for authentication, this can lead to further vulnerabilities similar to SQL Injection.
  LDAP Injection
LDAP Injection enables an attacker to inject LDAP statements potentially granting permission to run unauthorized queries, or modify content inside the LDAP tree.
  Header Injection
  Other Vulnerability
This category comprises other attack vectors such as manipulating the PHP runtime, loading custom extensions, freezing the runtime, or similar.
  Regex Injection
Regex Injection enables an attacker to execute arbitrary code in your PHP process.
  XML Injection
XML Injection enables an attacker to read files on your local filesystem including configuration files, or can be abused to freeze your web-server process.
  Variable Injection
Variable Injection enables an attacker to overwrite program variables with custom data, and can lead to further vulnerabilities.
Unfortunately, the security analysis is currently not available for your project. If you are a non-commercial open-source project, please contact support to gain access.

src/Date.php (6 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
3
namespace HMLB\Date;
4
5
use Closure;
6
use DatePeriod;
7
use DateTimeImmutable;
8
use DateTimeInterface;
9
use DateTimeZone;
10
use HMLB\Date\Translation\DateLocalizationCapabilities;
11
use InvalidArgumentException;
12
13
/**
14
 * An immutable Date objects with a rich API.
15
 *
16
 * @author Hugues Maignol <[email protected]>
17
 */
18
class Date extends DateTimeImmutable
19
{
20
    use DateLocalizationCapabilities;
21
22
    const ATOM = 'Y-m-d\TH:i:sP';
23
    const COOKIE = 'l, d-M-y H:i:s T';
24
    const ISO8601 = 'Y-m-d\TH:i:sO';
25
    const RFC822 = 'D, d M y H:i:s O';
26
    const RFC850 = 'l, d-M-y H:i:s T';
27
    const RFC1036 = 'D, d M y H:i:s O';
28
    const RFC1123 = 'D, d M Y H:i:s O';
29
    const RFC2822 = 'D, d M Y H:i:s O';
30
    const RFC3339 = 'Y-m-d\TH:i:sP';
31
    const RSS = 'D, d M Y H:i:s O';
32
    const W3C = 'Y-m-d\TH:i:sP';
33
34
    /**
35
     * The day constants.
36
     */
37
    const SUNDAY = 0;
38
    const MONDAY = 1;
39
    const TUESDAY = 2;
40
    const WEDNESDAY = 3;
41
    const THURSDAY = 4;
42
    const FRIDAY = 5;
43
    const SATURDAY = 6;
44
45
    /**
46
     * Names of days of the week.
47
     *
48
     * @var array
49
     */
50
    protected static $days = [
51
        self::SUNDAY => 'Sunday',
52
        self::MONDAY => 'Monday',
53
        self::TUESDAY => 'Tuesday',
54
        self::WEDNESDAY => 'Wednesday',
55
        self::THURSDAY => 'Thursday',
56
        self::FRIDAY => 'Friday',
57
        self::SATURDAY => 'Saturday',
58
    ];
59
60
    /**
61
     * Terms used to detect if a time passed is a relative date for testing purposes.
62
     *
63
     * @var array
64
     */
65
    protected static $relativeKeywords = [
66
        'this',
67
        'next',
68
        'last',
69
        'tomorrow',
70
        'yesterday',
71
        '+',
72
        '-',
73
        'first',
74
        'last',
75
        'ago',
76
    ];
77
78
    /**
79
     * Number of X in Y.
80
     */
81
    const YEARS_PER_CENTURY = 100;
82
    const YEARS_PER_DECADE = 10;
83
    const MONTHS_PER_YEAR = 12;
84
    const WEEKS_PER_YEAR = 52;
85
    const DAYS_PER_WEEK = 7;
86
    const HOURS_PER_DAY = 24;
87
    const MINUTES_PER_HOUR = 60;
88
    const SECONDS_PER_MINUTE = 60;
89
90
    /**
91
     * Default format to use for __toString method when type juggling occurs.
92
     *
93
     * @var string
94
     */
95
    const DEFAULT_TO_STRING_FORMAT = 'Y-m-d H:i:s';
96
97
    /**
98
     * Format to use for __toString method when type juggling occurs.
99
     *
100
     * @var string
101
     */
102
    protected static $toStringFormat = self::DEFAULT_TO_STRING_FORMAT;
103
104
    /**
105
     * First day of week.
106
     *
107
     * @var int
108
     */
109
    protected static $weekStartsAt = self::MONDAY;
110
111
    /**
112
     * Last day of week.
113
     *
114
     * @var int
115
     */
116
    protected static $weekEndsAt = self::SUNDAY;
117
118
    /**
119
     * Days of weekend.
120
     *
121
     * @var array
122
     */
123
    protected static $weekendDays = [self::SATURDAY, self::SUNDAY];
124
125
    /**
126
     * A test Date instance to be returned when now instances are created.
127
     *
128
     * @var Date
129
     */
130
    protected static $testNow;
131
132
    /**
133
     * Creates a DateTimeZone from a string or a DateTimeZone.
134
     *
135
     * @param DateTimeZone|string|null $object
136
     *
137
     * @throws InvalidArgumentException
138
     *
139
     * @return DateTimeZone
140
     */
141
    protected static function safeCreateDateTimeZone($object)
142
    {
143
        if ($object === null) {
144
            // Don't return null... avoid Bug #52063 in PHP <5.3.6
145
            return new DateTimeZone(date_default_timezone_get());
146
        }
147
148
        if ($object instanceof DateTimeZone) {
149
            return $object;
150
        }
151
152
        $tz = @timezone_open((string) $object);
153
154
        if ($tz === false) {
155
            throw new InvalidArgumentException('Unknown or bad timezone ('.$object.')');
156
        }
157
158
        return $tz;
159
    }
160
161
    ///////////////////////////////////////////////////////////////////
162
    //////////////////////////// CONSTRUCTORS /////////////////////////
163
    ///////////////////////////////////////////////////////////////////
164
165
    /**
166
     * Create a new Date instance.
167
     *
168
     * Please see the testing aids section (specifically static::setTestNow())
169
     * for more on the possibility of this constructor returning a test instance.
170
     *
171
     * @param string                   $time
172
     * @param DateTimeZone|string|null $tz
173
     */
174
    public function __construct($time = 'now', $tz = null)
175
    {
176
        // If the class has a test now set and we are trying to create a now()
177
        // instance then override as required
178
        if (static::hasTestNow() && (empty($time) || $time === 'now' || static::hasRelativeKeywords($time))) {
179
            $testInstance = clone static::getTestNow();
180
            if (static::hasRelativeKeywords($time)) {
181
                $testInstance = $testInstance->modify($time);
182
            }
183
184
            //shift the time according to the given time zone
185
            if ($tz !== null && $tz !== static::getTestNow()->getTimezone()) {
186
                $testInstance = $testInstance->setTimezone($tz);
187
            } else {
188
                $tz = $testInstance->getTimezone();
189
            }
190
191
            $time = $testInstance->toDateTimeString();
192
        }
193
194
        parent::__construct($time, static::safeCreateDateTimeZone($tz));
195
    }
196
197
    /**
198
     * Create a Date instance from a DateTime one.
199
     *
200
     * @param DateTimeInterface $dt
201
     *
202
     * @return static
203
     */
204
    public static function instance(DateTimeInterface $dt)
205
    {
206
        return new static($dt->format('Y-m-d H:i:s.u'), $dt->getTimeZone());
207
    }
208
209
    /**
210
     * Create a date instance from a string.  This is an alias for the
211
     * constructor that allows better fluent syntax as it allows you to do
212
     * Date::parse('Monday next week')->fn() rather than
213
     * (new Date('Monday next week'))->fn().
214
     *
215
     * @param string                   $time
216
     * @param DateTimeZone|string|null $tz
217
     *
218
     * @return static
219
     */
220
    public static function parse($time = 'now', $tz = null)
221
    {
222
        return new static($time, $tz);
223
    }
224
225
    /**
226
     * Get a Date instance for the current date and time.
227
     *
228
     * @param DateTimeZone|string|null $tz
229
     *
230
     * @return static
231
     */
232
    public static function now($tz = null)
233
    {
234
        return new static('now', $tz);
235
    }
236
237
    /**
238
     * Create a Date instance for today.
239
     *
240
     * @param DateTimeZone|string|null $tz
241
     *
242
     * @return static
243
     */
244
    public static function today($tz = null)
245
    {
246
        return static::now($tz)->startOfDay();
247
    }
248
249
    /**
250
     * Create a Date instance for tomorrow.
251
     *
252
     * @param DateTimeZone|string|null $tz
253
     *
254
     * @return static
255
     */
256
    public static function tomorrow($tz = null)
257
    {
258
        return static::today($tz)->addDay();
259
    }
260
261
    /**
262
     * Create a Date instance for yesterday.
263
     *
264
     * @param DateTimeZone|string|null $tz
265
     *
266
     * @return static
267
     */
268
    public static function yesterday($tz = null)
269
    {
270
        return static::today($tz)->subDay();
271
    }
272
273
    /**
274
     * Create a Date instance for the greatest supported date.
275
     *
276
     * @return Date
277
     */
278 View Code Duplication
    public static function maxValue()
0 ignored issues
show
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...
279
    {
280
        if (PHP_INT_SIZE === 4) {
281
            // 32 bit (and additionally Windows 64 bit)
282
            return static::createFromTimestamp(PHP_INT_MAX);
283
        }
284
285
        // 64 bit
286
        return static::create(9999, 12, 31, 23, 59, 59);
287
    }
288
289
    /**
290
     * Create a Date instance for the lowest supported date.
291
     *
292
     * @return Date
293
     */
294 View Code Duplication
    public static function minValue()
0 ignored issues
show
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...
295
    {
296
        if (PHP_INT_SIZE === 4) {
297
            // 32 bit (and additionally Windows 64 bit)
298
            return static::createFromTimestamp(~PHP_INT_MAX);
299
        }
300
301
        // 64 bit
302
        return static::create(1, 1, 1, 0, 0, 0);
303
    }
304
305
    /**
306
     * Create a new Date instance from a specific date and time.
307
     *
308
     * If any of $year, $month or $day are set to null their now() values
309
     * will be used.
310
     *
311
     * If $hour is null it will be set to its now() value and the default values
312
     * for $minute and $second will be their now() values.
313
     * If $hour is not null then the default values for $minute and $second
314
     * will be 0.
315
     *
316
     * @param int|null                 $year
317
     * @param int|null                 $month
318
     * @param int|null                 $day
319
     * @param int|null                 $hour
320
     * @param int|null                 $minute
321
     * @param int|null                 $second
322
     * @param DateTimeZone|string|null $tz
323
     *
324
     * @return static
325
     */
326
    public static function create(
327
        $year = null,
328
        $month = null,
329
        $day = null,
330
        $hour = null,
331
        $minute = null,
332
        $second = null,
333
        $tz = null
334
    ) {
335
        $year = $year === null ? date('Y') : $year;
336
        $month = $month === null ? date('n') : $month;
337
        $day = $day === null ? date('j') : $day;
338
339
        if ($hour === null) {
340
            $hour = date('G');
341
            $minute = $minute === null ? date('i') : $minute;
342
            $second = $second === null ? date('s') : $second;
343
        } else {
344
            $minute = $minute === null ? 0 : $minute;
345
            $second = $second === null ? 0 : $second;
346
        }
347
348
        return static::createFromFormat(
349
            'Y-n-j G:i:s',
350
            sprintf('%s-%s-%s %s:%02s:%02s', $year, $month, $day, $hour, $minute, $second),
351
            $tz
352
        );
353
    }
354
355
    /**
356
     * Create a Date instance from just a date. The time portion is set to now.
357
     *
358
     * @param int|null                 $year
359
     * @param int|null                 $month
360
     * @param int|null                 $day
361
     * @param DateTimeZone|string|null $tz
362
     *
363
     * @return static
364
     */
365
    public static function createFromDate($year = null, $month = null, $day = null, $tz = null)
366
    {
367
        return static::create($year, $month, $day, null, null, null, $tz);
368
    }
369
370
    /**
371
     * Create a Date instance from just a time. The date portion is set to today.
372
     *
373
     * @param int|null                 $hour
374
     * @param int|null                 $minute
375
     * @param int|null                 $second
376
     * @param DateTimeZone|string|null $tz
377
     *
378
     * @return static
379
     */
380
    public static function createFromTime($hour = null, $minute = null, $second = null, $tz = null)
381
    {
382
        return static::create(null, null, null, $hour, $minute, $second, $tz);
383
    }
384
385
    /**
386
     * Create a Date instance from a specific format.
387
     *
388
     * @param string                   $format
389
     * @param string                   $time
390
     * @param DateTimeZone|string|null $tz
391
     *
392
     * @throws InvalidArgumentException
393
     *
394
     * @return static
395
     */
396
    public static function createFromFormat($format, $time, $tz = null)
397
    {
398
        if ($tz !== null) {
399
            $dt = parent::createFromFormat($format, $time, static::safeCreateDateTimeZone($tz));
400
        } else {
401
            $dt = parent::createFromFormat($format, $time);
402
        }
403
404
        if ($dt instanceof DateTimeInterface) {
405
            return static::instance($dt);
406
        }
407
408
        $errors = static::getLastErrors();
409
        throw new InvalidArgumentException(implode(PHP_EOL, $errors['errors']));
410
    }
411
412
    /**
413
     * Create a Date instance from a timestamp.
414
     *
415
     * @param int                      $timestamp
416
     * @param DateTimeZone|string|null $tz
417
     *
418
     * @return static
419
     */
420
    public static function createFromTimestamp($timestamp, $tz = null)
421
    {
422
        return static::now($tz)->setTimestamp($timestamp);
423
    }
424
425
    /**
426
     * Create a Date instance from an UTC timestamp.
427
     *
428
     * @param int $timestamp
429
     *
430
     * @return static
431
     */
432
    public static function createFromTimestampUTC($timestamp)
433
    {
434
        return new static('@'.$timestamp);
435
    }
436
437
    /**
438
     * Get a copy of the instance.
439
     *
440
     * @return static
441
     */
442
    public function copy()
443
    {
444
        return static::instance($this);
445
    }
446
447
    ///////////////////////////////////////////////////////////////////
448
    ///////////////////////// GETTERS AND SETTERS /////////////////////
449
    ///////////////////////////////////////////////////////////////////
450
451
    /**
452
     * @return int
453
     */
454
    public function getYear()
455
    {
456
        return (int) $this->format('Y');
457
    }
458
459
    /**
460
     * @return int
461
     */
462
    public function getYearIso()
463
    {
464
        return (int) $this->format('o');
465
    }
466
467
    /**
468
     * @return int
469
     */
470
    public function getMonth()
471
    {
472
        return (int) $this->format('n');
473
    }
474
475
    /**
476
     * @return int
477
     */
478
    public function getDay()
479
    {
480
        return (int) $this->format('j');
481
    }
482
483
    /**
484
     * @return int
485
     */
486
    public function getHour()
487
    {
488
        return (int) $this->format('G');
489
    }
490
491
    /**
492
     * @return int
493
     */
494
    public function getMinute()
495
    {
496
        return (int) $this->format('i');
497
    }
498
499
    /**
500
     * @return int
501
     */
502
    public function getSecond()
503
    {
504
        return (int) $this->format('s');
505
    }
506
507
    /**
508
     * @return int
509
     */
510
    public function getMicro()
511
    {
512
        return (int) $this->format('u');
513
    }
514
515
    /**
516
     * @return int
517
     */
518
    public function getDayOfWeek()
519
    {
520
        return (int) $this->format('w');
521
    }
522
523
    /**
524
     * @return int
525
     */
526
    public function getDayOfYear()
527
    {
528
        return (int) $this->format('z');
529
    }
530
531
    /**
532
     * @return int
533
     */
534
    public function getWeekOfYear()
535
    {
536
        return (int) $this->format('W');
537
    }
538
539
    /**
540
     * @return int
541
     */
542
    public function getDaysInMonth()
543
    {
544
        return (int) $this->format('t');
545
    }
546
547
    /**
548
     * @return int
549
     */
550
    public function getTimestamp()
551
    {
552
        return (int) $this->format('U');
553
    }
554
555
    /**
556
     * @return int
557
     */
558
    public function getWeekOfMonth()
559
    {
560
        return (int) ceil($this->getDay() / static::DAYS_PER_WEEK);
561
    }
562
563
    /**
564
     * @return int
565
     */
566
    public function getAge()
567
    {
568
        return (int) $this->diffInYears();
569
    }
570
571
    /**
572
     * @return int
573
     */
574
    public function getQuarter()
575
    {
576
        return (int) ceil($this->getMonth() / 3);
577
    }
578
579
    /**
580
     * @return int
581
     */
582
    public function getOffsetHours()
583
    {
584
        return $this->getOffset() / static::SECONDS_PER_MINUTE / static::MINUTES_PER_HOUR;
585
    }
586
587
    /**
588
     * @return int
589
     */
590
    public function getDst()
591
    {
592
        return $this->format('I') === '1';
593
    }
594
595
    /**
596
     * @return int
597
     */
598
    public function getDaylightSavingTime()
599
    {
600
        return $this->getDst();
601
    }
602
603
    /**
604
     * @return int
605
     */
606
    public function getLocal()
607
    {
608
        return $this->getOffset() === $this->setTimezone(date_default_timezone_get())->getOffset();
609
    }
610
611
    /**
612
     * @return bool
613
     */
614
    public function isUtc()
615
    {
616
        return $this->getOffset() === 0;
617
    }
618
619
    /**
620
     * @return int
621
     */
622
    public function getTimezoneName()
623
    {
624
        return $this->getTimezone()->getName();
625
    }
626
627
    /**
628
     * Set the instance's year.
629
     *
630
     * @param int $value
631
     *
632
     * @return static
633
     */
634
    public function year($value)
635
    {
636
        return $this->setDate($value, $this->getMonth(), $this->getDay());
637
    }
638
639
    /**
640
     * Set the instance's month.
641
     *
642
     * @param int $value
643
     *
644
     * @return static
645
     */
646
    public function month($value)
647
    {
648
        return $this->setDate($this->getYear(), $value, $this->getDay());
649
    }
650
651
    /**
652
     * Set the instance's day.
653
     *
654
     * @param int $value
655
     *
656
     * @return static
657
     */
658
    public function day($value)
659
    {
660
        return $this->setDate($this->getYear(), $this->getMonth(), $value);
661
    }
662
663
    /**
664
     * Set the instance's hour.
665
     *
666
     * @param int $value
667
     *
668
     * @return static
669
     */
670
    public function hour($value)
671
    {
672
        return $this->setTime($value, $this->getMinute(), $this->getSecond());
673
    }
674
675
    /**
676
     * Set the instance's minute.
677
     *
678
     * @param int $value
679
     *
680
     * @return static
681
     */
682
    public function minute($value)
683
    {
684
        return $this->setTime($this->getHour(), $value, $this->getSecond());
685
    }
686
687
    /**
688
     * Set the instance's second.
689
     *
690
     * @param int $value
691
     *
692
     * @return static
693
     */
694
    public function second($value)
695
    {
696
        return $this->setTime($this->getHour(), $this->getMinute(), $value);
697
    }
698
699
    /**
700
     * Set the date and time all together.
701
     *
702
     * @param int $year
703
     * @param int $month
704
     * @param int $day
705
     * @param int $hour
706
     * @param int $minute
707
     * @param int $second
708
     *
709
     * @return static
710
     */
711
    public function setDateTime($year, $month, $day, $hour, $minute = 0, $second = 0)
712
    {
713
        return $this->setDate($year, $month, $day)->setTime($hour, $minute, $second);
714
    }
715
716
    /**
717
     * Set the time by time string.
718
     *
719
     * @param string $time
720
     *
721
     * @return static
722
     */
723
    public function setTimeFromTimeString($time)
724
    {
725
        $time = explode(':', $time);
726
727
        $hour = (int) $time[0];
728
        $minute = isset($time[1]) ? (int) $time[1] : 0;
729
        $second = isset($time[2]) ? (int) $time[2] : 0;
730
731
        return $this->setTime($hour, $minute, $second);
732
    }
733
734
    /**
735
     * Set the instance's timestamp.
736
     *
737
     * @param int $value
738
     *
739
     * @return static
740
     */
741
    public function timestamp($value)
742
    {
743
        return $this->setTimestamp($value);
744
    }
745
746
    /**
747
     * Alias for setTimezone().
748
     *
749
     * @param DateTimeZone|string $value
750
     *
751
     * @return static
752
     */
753
    public function timezone($value)
754
    {
755
        return $this->setTimezone($value);
756
    }
757
758
    /**
759
     * Set the instance's timezone from a string or object.
760
     *
761
     * @param DateTimeZone|string $value
762
     *
763
     * @return static
764
     */
765
    public function setTimezone($value)
766
    {
767
        return parent::setTimezone(static::safeCreateDateTimeZone($value));
768
    }
769
770
    ///////////////////////////////////////////////////////////////////
771
    /////////////////////// WEEK SPECIAL DAYS /////////////////////////
772
    ///////////////////////////////////////////////////////////////////
773
774
    /**
775
     * Get the first day of week.
776
     *
777
     * @return int
778
     */
779
    public static function getWeekStartsAt()
780
    {
781
        return static::$weekStartsAt;
782
    }
783
784
    /**
785
     * Set the first day of week.
786
     *
787
     * @param int
788
     */
789
    public static function setWeekStartsAt($day)
790
    {
791
        static::$weekStartsAt = $day;
792
    }
793
794
    /**
795
     * Get the last day of week.
796
     *
797
     * @return int
798
     */
799
    public static function getWeekEndsAt()
800
    {
801
        return static::$weekEndsAt;
802
    }
803
804
    /**
805
     * Set the first day of week.
806
     *
807
     * @param int
808
     */
809
    public static function setWeekEndsAt($day)
810
    {
811
        static::$weekEndsAt = $day;
812
    }
813
814
    /**
815
     * Get weekend days.
816
     *
817
     * @return array
818
     */
819
    public static function getWeekendDays()
820
    {
821
        return static::$weekendDays;
822
    }
823
824
    /**
825
     * Set weekend days.
826
     *
827
     * @param array
828
     */
829
    public static function setWeekendDays($days)
830
    {
831
        static::$weekendDays = $days;
832
    }
833
834
    ///////////////////////////////////////////////////////////////////
835
    ///////////////////////// TESTING AIDS ////////////////////////////
836
    ///////////////////////////////////////////////////////////////////
837
838
    /**
839
     * Set a Date instance (real or mock) to be returned when a "now"
840
     * instance is created.  The provided instance will be returned
841
     * specifically under the following conditions:
842
     *   - A call to the static now() method, ex. Date::now()
843
     *   - When a null (or blank string) is passed to the constructor or parse(), ex. new Date(null)
844
     *   - When the string "now" is passed to the constructor or parse(), ex. new Date('now').
845
     *
846
     * Note the timezone parameter was left out of the examples above and
847
     * has no affect as the mock value will be returned regardless of its value.
848
     *
849
     * To clear the test instance call this method using the default
850
     * parameter of null.
851
     *
852
     * @param Date|null $testNow
853
     */
854
    public static function setTestNow(Date $testNow = null)
855
    {
856
        static::$testNow = $testNow;
857
    }
858
859
    /**
860
     * Get the Date instance (real or mock) to be returned when a "now"
861
     * instance is created.
862
     *
863
     * @return static the current instance used for testing
864
     */
865
    public static function getTestNow()
866
    {
867
        return static::$testNow;
868
    }
869
870
    /**
871
     * Determine if there is a valid test instance set. A valid test instance
872
     * is anything that is not null.
873
     *
874
     * @return bool true if there is a test instance, otherwise false
875
     */
876
    public static function hasTestNow()
877
    {
878
        return static::getTestNow() !== null;
879
    }
880
881
    /**
882
     * Determine if there is a relative keyword in the time string, this is to
883
     * create dates relative to now for test instances. e.g.: next tuesday.
884
     *
885
     * @param string $time
886
     *
887
     * @return bool true if there is a keyword, otherwise false
888
     */
889
    public static function hasRelativeKeywords($time)
890
    {
891
        // skip common format with a '-' in it
892
        if (preg_match('/[0-9]{4}-[0-9]{1,2}-[0-9]{1,2}/', $time) !== 1) {
893
            foreach (static::$relativeKeywords as $keyword) {
894
                if (stripos($time, $keyword) !== false) {
895
                    return true;
896
                }
897
            }
898
        }
899
900
        return false;
901
    }
902
903
    ///////////////////////////////////////////////////////////////////
904
    /////////////////////// STRING FORMATTING /////////////////////////
905
    ///////////////////////////////////////////////////////////////////
906
907
    /**
908
     * Format the instance with the current locale.  You can set the current
909
     * locale using setlocale() http://php.net/setlocale.
910
     *
911
     * @param string $format
912
     *
913
     * @return string
914
     */
915
    public function formatLocalized($format)
916
    {
917
        // Check for Windows to find and replace the %e
918
        // modifier correctly
919
        if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') {
920
            $format = preg_replace('#(?<!%)((?:%%)*)%e#', '\1%#d', $format);
921
        }
922
923
        return strftime($format, strtotime($this));
924
    }
925
926
    /**
927
     * Reset the format used to the default when type juggling a Date instance to a string.
928
     */
929
    public static function resetToStringFormat()
930
    {
931
        static::setToStringFormat(static::DEFAULT_TO_STRING_FORMAT);
932
    }
933
934
    /**
935
     * Set the default format used when type juggling a Date instance to a string.
936
     *
937
     * @param string $format
938
     */
939
    public static function setToStringFormat($format)
940
    {
941
        static::$toStringFormat = $format;
942
    }
943
944
    /**
945
     * Format the instance as a string using the set format.
946
     *
947
     * @return string
948
     */
949
    public function __toString()
950
    {
951
        return $this->format(static::$toStringFormat);
952
    }
953
954
    /**
955
     * Format the instance as date.
956
     *
957
     * @return string
958
     */
959
    public function toDateString()
960
    {
961
        return $this->format('Y-m-d');
962
    }
963
964
    /**
965
     * Format the instance as a readable date.
966
     *
967
     * @return string
968
     */
969
    public function toFormattedDateString()
970
    {
971
        return $this->format('M j, Y');
972
    }
973
974
    /**
975
     * Format the instance as time.
976
     *
977
     * @return string
978
     */
979
    public function toTimeString()
980
    {
981
        return $this->format('H:i:s');
982
    }
983
984
    /**
985
     * Format the instance as date and time.
986
     *
987
     * @return string
988
     */
989
    public function toDateTimeString()
990
    {
991
        return $this->format('Y-m-d H:i:s');
992
    }
993
994
    /**
995
     * Format the instance with day, date and time.
996
     *
997
     * @return string
998
     */
999
    public function toDayDateTimeString()
1000
    {
1001
        return $this->format('D, M j, Y g:i A');
1002
    }
1003
1004
    /**
1005
     * Format the instance as ATOM.
1006
     *
1007
     * @return string
1008
     */
1009
    public function toAtomString()
1010
    {
1011
        return $this->format(static::ATOM);
1012
    }
1013
1014
    /**
1015
     * Format the instance as COOKIE.
1016
     *
1017
     * @return string
1018
     */
1019
    public function toCookieString()
1020
    {
1021
        return $this->format(static::COOKIE);
1022
    }
1023
1024
    /**
1025
     * Format the instance as ISO8601.
1026
     *
1027
     * @return string
1028
     */
1029
    public function toIso8601String()
1030
    {
1031
        return $this->format(static::ISO8601);
1032
    }
1033
1034
    /**
1035
     * Format the instance as RFC822.
1036
     *
1037
     * @return string
1038
     */
1039
    public function toRfc822String()
1040
    {
1041
        return $this->format(static::RFC822);
1042
    }
1043
1044
    /**
1045
     * Format the instance as RFC850.
1046
     *
1047
     * @return string
1048
     */
1049
    public function toRfc850String()
1050
    {
1051
        return $this->format(static::RFC850);
1052
    }
1053
1054
    /**
1055
     * Format the instance as RFC1036.
1056
     *
1057
     * @return string
1058
     */
1059
    public function toRfc1036String()
1060
    {
1061
        return $this->format(static::RFC1036);
1062
    }
1063
1064
    /**
1065
     * Format the instance as RFC1123.
1066
     *
1067
     * @return string
1068
     */
1069
    public function toRfc1123String()
1070
    {
1071
        return $this->format(static::RFC1123);
1072
    }
1073
1074
    /**
1075
     * Format the instance as RFC2822.
1076
     *
1077
     * @return string
1078
     */
1079
    public function toRfc2822String()
1080
    {
1081
        return $this->format(static::RFC2822);
1082
    }
1083
1084
    /**
1085
     * Format the instance as RFC3339.
1086
     *
1087
     * @return string
1088
     */
1089
    public function toRfc3339String()
1090
    {
1091
        return $this->format(static::RFC3339);
1092
    }
1093
1094
    /**
1095
     * Format the instance as RSS.
1096
     *
1097
     * @return string
1098
     */
1099
    public function toRssString()
1100
    {
1101
        return $this->format(static::RSS);
1102
    }
1103
1104
    /**
1105
     * Format the instance as W3C.
1106
     *
1107
     * @return string
1108
     */
1109
    public function toW3cString()
1110
    {
1111
        return $this->format(static::W3C);
1112
    }
1113
1114
    ///////////////////////////////////////////////////////////////////
1115
    ////////////////////////// COMPARISONS ////////////////////////////
1116
    ///////////////////////////////////////////////////////////////////
1117
1118
    /**
1119
     * Determines if the instance is equal to another.
1120
     *
1121
     * @param Date $dt
1122
     *
1123
     * @return bool
1124
     */
1125
    public function equals(Date $dt)
1126
    {
1127
        return $this == $dt;
1128
    }
1129
1130
    /**
1131
     * Determines if the instance is not equal to another.
1132
     *
1133
     * @param Date $dt
1134
     *
1135
     * @return bool
1136
     */
1137
    public function notEquals(Date $dt)
1138
    {
1139
        return !$this->equals($dt);
1140
    }
1141
1142
    /**
1143
     * Determines if the instance is greater (after) than another.
1144
     *
1145
     * @param Date $dt
1146
     *
1147
     * @return bool
1148
     */
1149
    public function isAfter(Date $dt)
1150
    {
1151
        return $this > $dt;
1152
    }
1153
1154
    /**
1155
     * Determines if the instance is greater (after) than or equal to another.
1156
     *
1157
     * @param Date $dt
1158
     *
1159
     * @return bool
1160
     */
1161
    public function isAfterOrEquals(Date $dt)
1162
    {
1163
        return $this >= $dt;
1164
    }
1165
1166
    /**
1167
     * Determines if the instance is less (before) than another.
1168
     *
1169
     * @param Date $dt
1170
     *
1171
     * @return bool
1172
     */
1173
    public function isBefore(Date $dt)
1174
    {
1175
        return $this < $dt;
1176
    }
1177
1178
    /**
1179
     * Determines if the instance is less (before) or equal to another.
1180
     *
1181
     * @param Date $dt
1182
     *
1183
     * @return bool
1184
     */
1185
    public function isBeforeOrEquals(Date $dt)
1186
    {
1187
        return $this <= $dt;
1188
    }
1189
1190
    /**
1191
     * Determines if the instance is between two others.
1192
     *
1193
     * @param Date $dt1
1194
     * @param Date $dt2
1195
     * @param bool $equal Indicates if a > and < comparison should be used or <= or >=
1196
     *
1197
     * @return bool
1198
     */
1199
    public function isBetween(Date $dt1, Date $dt2, $equal = true)
1200
    {
1201
        if ($dt1->isAfter($dt2)) {
1202
            $temp = $dt1;
1203
            $dt1 = $dt2;
1204
            $dt2 = $temp;
1205
        }
1206
1207
        if ($equal) {
1208
            return $this->isAfterOrEquals($dt1) && $this->isBeforeOrEquals($dt2);
1209
        }
1210
1211
        return $this->isAfter($dt1) && $this->isBefore($dt2);
1212
    }
1213
1214
    /**
1215
     * Get the closest date from the instance.
1216
     *
1217
     * @param Date $dt1
1218
     * @param Date $dt2
1219
     *
1220
     * @return static
1221
     */
1222
    public function closest(Date $dt1, Date $dt2)
1223
    {
1224
        return $this->diffInSeconds($dt1) < $this->diffInSeconds($dt2) ? $dt1 : $dt2;
1225
    }
1226
1227
    /**
1228
     * Get the farthest date from the instance.
1229
     *
1230
     * @param Date $dt1
1231
     * @param Date $dt2
1232
     *
1233
     * @return static
1234
     */
1235
    public function farthest(Date $dt1, Date $dt2)
1236
    {
1237
        return $this->diffInSeconds($dt1) > $this->diffInSeconds($dt2) ? $dt1 : $dt2;
1238
    }
1239
1240
    /**
1241
     * Get the minimum instance between a given instance (default now) and the current instance.
1242
     *
1243
     * @param Date|null $dt
1244
     *
1245
     * @return static
1246
     */
1247
    public function min(Date $dt = null)
1248
    {
1249
        $dt = $dt ?: static::now($this->getTimezone());
1250
1251
        return $this->isBefore($dt) ? clone $this : clone $dt;
1252
    }
1253
1254
    /**
1255
     * Get the maximum instance between a given instance (default now) and the current instance.
1256
     *
1257
     * @param Date|null $dt
1258
     *
1259
     * @return static
1260
     */
1261
    public function max(Date $dt = null)
1262
    {
1263
        $dt = $dt ?: static::now($this->getTimezone());
1264
1265
        return $this->isAfter($dt) ? clone $this : clone $dt;
1266
    }
1267
1268
    /**
1269
     * Determines if the instance is a weekday.
1270
     *
1271
     * @return bool
1272
     */
1273
    public function isWeekday()
1274
    {
1275
        return !$this->isWeekend();
1276
    }
1277
1278
    /**
1279
     * Determines if the instance is a weekend day.
1280
     *
1281
     * @return bool
1282
     */
1283
    public function isWeekend()
1284
    {
1285
        return in_array($this->getDayOfWeek(), self::$weekendDays);
1286
    }
1287
1288
    /**
1289
     * Determines if the instance is yesterday.
1290
     *
1291
     * @return bool
1292
     */
1293
    public function isYesterday()
1294
    {
1295
        return $this->toDateString() === static::yesterday($this->getTimezone())->toDateString();
1296
    }
1297
1298
    /**
1299
     * Determines if the instance is today.
1300
     *
1301
     * @return bool
1302
     */
1303
    public function isToday()
1304
    {
1305
        return $this->toDateString() === static::now($this->getTimezone())->toDateString();
1306
    }
1307
1308
    /**
1309
     * Determines if the instance is tomorrow.
1310
     *
1311
     * @return bool
1312
     */
1313
    public function isTomorrow()
1314
    {
1315
        return $this->toDateString() === static::tomorrow($this->getTimezone())->toDateString();
1316
    }
1317
1318
    /**
1319
     * Determines if the instance is in the future, ie. greater (after) than now.
1320
     *
1321
     * @return bool
1322
     */
1323
    public function isFuture()
1324
    {
1325
        return $this->isAfter(static::now($this->getTimezone()));
1326
    }
1327
1328
    /**
1329
     * Determines if the instance is in the past, ie. less (before) than now.
1330
     *
1331
     * @return bool
1332
     */
1333
    public function isPast()
1334
    {
1335
        return $this->isBefore(static::now($this->getTimezone()));
1336
    }
1337
1338
    /**
1339
     * Determines if the instance is a leap year.
1340
     *
1341
     * @return bool
1342
     */
1343
    public function isLeapYear()
1344
    {
1345
        return $this->format('L') === '1';
1346
    }
1347
1348
    /**
1349
     * Checks if the passed in date is the same day as the instance current day.
1350
     *
1351
     * @param Date $dt
1352
     *
1353
     * @return bool
1354
     */
1355
    public function isSameDay(Date $dt)
1356
    {
1357
        return $this->toDateString() === $dt->toDateString();
1358
    }
1359
1360
    /**
1361
     * Checks if this day is a Sunday.
1362
     *
1363
     * @return bool
1364
     */
1365
    public function isSunday()
1366
    {
1367
        return $this->getDayOfWeek() === static::SUNDAY;
1368
    }
1369
1370
    /**
1371
     * Checks if this day is a Monday.
1372
     *
1373
     * @return bool
1374
     */
1375
    public function isMonday()
1376
    {
1377
        return $this->getDayOfWeek() === static::MONDAY;
1378
    }
1379
1380
    /**
1381
     * Checks if this day is a Tuesday.
1382
     *
1383
     * @return bool
1384
     */
1385
    public function isTuesday()
1386
    {
1387
        return $this->getDayOfWeek() === static::TUESDAY;
1388
    }
1389
1390
    /**
1391
     * Checks if this day is a Wednesday.
1392
     *
1393
     * @return bool
1394
     */
1395
    public function isWednesday()
1396
    {
1397
        return $this->getDayOfWeek() === static::WEDNESDAY;
1398
    }
1399
1400
    /**
1401
     * Checks if this day is a Thursday.
1402
     *
1403
     * @return bool
1404
     */
1405
    public function isThursday()
1406
    {
1407
        return $this->getDayOfWeek() === static::THURSDAY;
1408
    }
1409
1410
    /**
1411
     * Checks if this day is a Friday.
1412
     *
1413
     * @return bool
1414
     */
1415
    public function isFriday()
1416
    {
1417
        return $this->getDayOfWeek() === static::FRIDAY;
1418
    }
1419
1420
    /**
1421
     * Checks if this day is a Saturday.
1422
     *
1423
     * @return bool
1424
     */
1425
    public function isSaturday()
1426
    {
1427
        return $this->getDayOfWeek() === static::SATURDAY;
1428
    }
1429
1430
    ///////////////////////////////////////////////////////////////////
1431
    /////////////////// ADDITIONS AND SUBTRACTIONS ////////////////////
1432
    ///////////////////////////////////////////////////////////////////
1433
1434
    /**
1435
     * Add years to the instance. Positive $value travel forward while
1436
     * negative $value travel into the past.
1437
     *
1438
     * @param int $value
1439
     *
1440
     * @return static
1441
     */
1442
    public function addYears($value)
1443
    {
1444
        return $this->modify((int) $value.' year');
1445
    }
1446
1447
    /**
1448
     * Add a year to the instance.
1449
     *
1450
     * @param int $value
1451
     *
1452
     * @return static
1453
     */
1454
    public function addYear($value = 1)
1455
    {
1456
        return $this->addYears($value);
1457
    }
1458
1459
    /**
1460
     * Remove a year from the instance.
1461
     *
1462
     * @param int $value
1463
     *
1464
     * @return static
1465
     */
1466
    public function subYear($value = 1)
1467
    {
1468
        return $this->subYears($value);
1469
    }
1470
1471
    /**
1472
     * Remove years from the instance.
1473
     *
1474
     * @param int $value
1475
     *
1476
     * @return static
1477
     */
1478
    public function subYears($value)
1479
    {
1480
        return $this->addYears(-1 * $value);
1481
    }
1482
1483
    /**
1484
     * Add months to the instance. Positive $value travels forward while
1485
     * negative $value travels into the past.
1486
     *
1487
     * @param int $value
1488
     *
1489
     * @return static
1490
     */
1491
    public function addMonths($value)
1492
    {
1493
        return $this->modify((int) $value.' month');
1494
    }
1495
1496
    /**
1497
     * Add a month to the instance.
1498
     *
1499
     * @param int $value
1500
     *
1501
     * @return static
1502
     */
1503
    public function addMonth($value = 1)
1504
    {
1505
        return $this->addMonths($value);
1506
    }
1507
1508
    /**
1509
     * Remove a month from the instance.
1510
     *
1511
     * @param int $value
1512
     *
1513
     * @return static
1514
     */
1515
    public function subMonth($value = 1)
1516
    {
1517
        return $this->subMonths($value);
1518
    }
1519
1520
    /**
1521
     * Remove months from the instance.
1522
     *
1523
     * @param int $value
1524
     *
1525
     * @return static
1526
     */
1527
    public function subMonths($value)
1528
    {
1529
        return $this->addMonths(-1 * $value);
1530
    }
1531
1532
    /**
1533
     * Add months without overflowing to the instance. Positive $value
1534
     * travels forward while negative $value travels into the past.
1535
     *
1536
     * @param int $value
1537
     *
1538
     * @return static
1539
     */
1540
    public function addMonthsNoOverflow($value)
1541
    {
1542
        $date = $this->addMonths($value);
1543
1544
        if ($date->getDay() !== $this->getDay()) {
1545
            $date = $date->day(1)->subMonth();
1546
            $date = $date->day($date->getDaysInMonth());
1547
        }
1548
1549
        return $date;
1550
    }
1551
1552
    /**
1553
     * Add a month with no overflow to the instance.
1554
     **.
1555
     *
1556
     * @return static
1557
     */
1558
    public function addMonthNoOverflow()
1559
    {
1560
        return $this->addMonthsNoOverflow(1);
1561
    }
1562
1563
    /**
1564
     * Remove a month with no overflow from the instance.
1565
     *
1566
     * @param int $value
1567
     *
1568
     * @return static
1569
     */
1570
    public function subMonthNoOverflow($value = 1)
1571
    {
1572
        return $this->subMonthsNoOverflow($value);
1573
    }
1574
1575
    /**
1576
     * Remove months with no overflow from the instance.
1577
     *
1578
     * @param int $value
1579
     *
1580
     * @return static
1581
     */
1582
    public function subMonthsNoOverflow($value)
1583
    {
1584
        return $this->addMonthsNoOverflow(-1 * $value);
1585
    }
1586
1587
    /**
1588
     * Add days to the instance. Positive $value travels forward while
1589
     * negative $value travels into the past.
1590
     *
1591
     * @param int $value
1592
     *
1593
     * @return static
1594
     */
1595
    public function addDays($value)
1596
    {
1597
        return $this->modify((int) $value.' day');
1598
    }
1599
1600
    /**
1601
     * Add a day to the instance.
1602
     *
1603
     * @param int $value
1604
     *
1605
     * @return static
1606
     */
1607
    public function addDay($value = 1)
1608
    {
1609
        return $this->addDays($value);
1610
    }
1611
1612
    /**
1613
     * Remove a day from the instance.
1614
     *
1615
     * @param int $value
1616
     *
1617
     * @return static
1618
     */
1619
    public function subDay($value = 1)
1620
    {
1621
        return $this->subDays($value);
1622
    }
1623
1624
    /**
1625
     * Remove days from the instance.
1626
     *
1627
     * @param int $value
1628
     *
1629
     * @return static
1630
     */
1631
    public function subDays($value)
1632
    {
1633
        return $this->addDays(-1 * $value);
1634
    }
1635
1636
    /**
1637
     * Add weekdays to the instance. Positive $value travels forward while
1638
     * negative $value travels into the past.
1639
     *
1640
     * @param int $value
1641
     *
1642
     * @return static
1643
     */
1644
    public function addWeekdays($value)
1645
    {
1646
        // fix for php bug #54909
1647
        $t = $this->toTimeString();
1648
1649
        return $this->modify((int) $value.' weekday')->setTimeFromTimeString($t);
1650
    }
1651
1652
    /**
1653
     * Add a weekday to the instance.
1654
     *
1655
     * @param int $value
1656
     *
1657
     * @return static
1658
     */
1659
    public function addWeekday($value = 1)
1660
    {
1661
        return $this->addWeekdays($value);
1662
    }
1663
1664
    /**
1665
     * Remove a weekday from the instance.
1666
     *
1667
     * @param int $value
1668
     *
1669
     * @return static
1670
     */
1671
    public function subWeekday($value = 1)
1672
    {
1673
        return $this->subWeekdays($value);
1674
    }
1675
1676
    /**
1677
     * Remove weekdays from the instance.
1678
     *
1679
     * @param int $value
1680
     *
1681
     * @return static
1682
     */
1683
    public function subWeekdays($value)
1684
    {
1685
        return $this->addWeekdays(-1 * $value);
1686
    }
1687
1688
    /**
1689
     * Add weeks to the instance. Positive $value travels forward while
1690
     * negative $value travels into the past.
1691
     *
1692
     * @param int $value
1693
     *
1694
     * @return static
1695
     */
1696
    public function addWeeks($value)
1697
    {
1698
        return $this->modify((int) $value.' week');
1699
    }
1700
1701
    /**
1702
     * Add a week to the instance.
1703
     *
1704
     * @param int $value
1705
     *
1706
     * @return static
1707
     */
1708
    public function addWeek($value = 1)
1709
    {
1710
        return $this->addWeeks($value);
1711
    }
1712
1713
    /**
1714
     * Remove a week from the instance.
1715
     *
1716
     * @param int $value
1717
     *
1718
     * @return static
1719
     */
1720
    public function subWeek($value = 1)
1721
    {
1722
        return $this->subWeeks($value);
1723
    }
1724
1725
    /**
1726
     * Remove weeks to the instance.
1727
     *
1728
     * @param int $value
1729
     *
1730
     * @return static
1731
     */
1732
    public function subWeeks($value)
1733
    {
1734
        return $this->addWeeks(-1 * $value);
1735
    }
1736
1737
    /**
1738
     * Add hours to the instance. Positive $value travels forward while
1739
     * negative $value travels into the past.
1740
     *
1741
     * @param int $value
1742
     *
1743
     * @return static
1744
     */
1745
    public function addHours($value)
1746
    {
1747
        return $this->modify((int) $value.' hour');
1748
    }
1749
1750
    /**
1751
     * Add an hour to the instance.
1752
     *
1753
     * @param int $value
1754
     *
1755
     * @return static
1756
     */
1757
    public function addHour($value = 1)
1758
    {
1759
        return $this->addHours($value);
1760
    }
1761
1762
    /**
1763
     * Remove an hour from the instance.
1764
     *
1765
     * @param int $value
1766
     *
1767
     * @return static
1768
     */
1769
    public function subHour($value = 1)
1770
    {
1771
        return $this->subHours($value);
1772
    }
1773
1774
    /**
1775
     * Remove hours from the instance.
1776
     *
1777
     * @param int $value
1778
     *
1779
     * @return static
1780
     */
1781
    public function subHours($value)
1782
    {
1783
        return $this->addHours(-1 * $value);
1784
    }
1785
1786
    /**
1787
     * Add minutes to the instance. Positive $value travels forward while
1788
     * negative $value travels into the past.
1789
     *
1790
     * @param int $value
1791
     *
1792
     * @return static
1793
     */
1794
    public function addMinutes($value)
1795
    {
1796
        return $this->modify((int) $value.' minute');
1797
    }
1798
1799
    /**
1800
     * Add a minute to the instance.
1801
     *
1802
     * @param int $value
1803
     *
1804
     * @return static
1805
     */
1806
    public function addMinute($value = 1)
1807
    {
1808
        return $this->addMinutes($value);
1809
    }
1810
1811
    /**
1812
     * Remove a minute from the instance.
1813
     *
1814
     * @param int $value
1815
     *
1816
     * @return static
1817
     */
1818
    public function subMinute($value = 1)
1819
    {
1820
        return $this->subMinutes($value);
1821
    }
1822
1823
    /**
1824
     * Remove minutes from the instance.
1825
     *
1826
     * @param int $value
1827
     *
1828
     * @return static
1829
     */
1830
    public function subMinutes($value)
1831
    {
1832
        return $this->addMinutes(-1 * $value);
1833
    }
1834
1835
    /**
1836
     * Add seconds to the instance. Positive $value travels forward while
1837
     * negative $value travels into the past.
1838
     *
1839
     * @param int $value
1840
     *
1841
     * @return static
1842
     */
1843
    public function addSeconds($value)
1844
    {
1845
        return $this->modify((int) $value.' second');
1846
    }
1847
1848
    /**
1849
     * Add a second to the instance.
1850
     *
1851
     * @param int $value
1852
     *
1853
     * @return static
1854
     */
1855
    public function addSecond($value = 1)
1856
    {
1857
        return $this->addSeconds($value);
1858
    }
1859
1860
    /**
1861
     * Remove a second from the instance.
1862
     *
1863
     * @param int $value
1864
     *
1865
     * @return static
1866
     */
1867
    public function subSecond($value = 1)
1868
    {
1869
        return $this->subSeconds($value);
1870
    }
1871
1872
    /**
1873
     * Remove seconds from the instance.
1874
     *
1875
     * @param int $value
1876
     *
1877
     * @return static
1878
     */
1879
    public function subSeconds($value)
1880
    {
1881
        return $this->addSeconds(-1 * $value);
1882
    }
1883
1884
    ///////////////////////////////////////////////////////////////////
1885
    /////////////////////////// DIFFERENCES ///////////////////////////
1886
    ///////////////////////////////////////////////////////////////////
1887
1888
    /**
1889
     * Get the difference in years.
1890
     *
1891
     * @param Date|null $dt
1892
     * @param bool      $abs Get the absolute of the difference
1893
     *
1894
     * @return int
1895
     */
1896
    public function diffInYears(Date $dt = null, $abs = true)
1897
    {
1898
        $dt = $dt ?: static::now($this->getTimezone());
1899
1900
        return (int) $this->diff($dt, $abs)->format('%r%y');
1901
    }
1902
1903
    /**
1904
     * Get the difference in months.
1905
     *
1906
     * @param Date|null $dt
1907
     * @param bool      $abs Get the absolute of the difference
1908
     *
1909
     * @return int
1910
     */
1911
    public function diffInMonths(Date $dt = null, $abs = true)
1912
    {
1913
        $dt = $dt ?: static::now($this->getTimezone());
1914
1915
        return $this->diffInYears($dt, $abs) * static::MONTHS_PER_YEAR + (int) $this->diff($dt, $abs)->format('%r%m');
1916
    }
1917
1918
    /**
1919
     * Get the difference in weeks.
1920
     *
1921
     * @param Date|null $dt
1922
     * @param bool      $abs Get the absolute of the difference
1923
     *
1924
     * @return int
1925
     */
1926
    public function diffInWeeks(Date $dt = null, $abs = true)
1927
    {
1928
        return (int) ($this->diffInDays($dt, $abs) / static::DAYS_PER_WEEK);
1929
    }
1930
1931
    /**
1932
     * Get the difference in days.
1933
     *
1934
     * @param Date|null $dt
1935
     * @param bool      $abs Get the absolute of the difference
1936
     *
1937
     * @return int
1938
     */
1939
    public function diffInDays(Date $dt = null, $abs = true)
1940
    {
1941
        $dt = $dt ?: static::now($this->getTimezone());
1942
1943
        return (int) $this->diff($dt, $abs)->format('%r%a');
1944
    }
1945
1946
    /**
1947
     * Get the difference in days using a filter closure.
1948
     *
1949
     * @param Closure   $callback
1950
     * @param Date|null $dt
1951
     * @param bool      $abs      Get the absolute of the difference
1952
     *
1953
     * @return int
1954
     */
1955
    public function diffInDaysFiltered(Closure $callback, Date $dt = null, $abs = true)
1956
    {
1957
        return $this->diffFiltered(Interval::day(), $callback, $dt, $abs);
1958
    }
1959
1960
    /**
1961
     * Get the difference in hours using a filter closure.
1962
     *
1963
     * @param Closure   $callback
1964
     * @param Date|null $dt
1965
     * @param bool      $abs      Get the absolute of the difference
1966
     *
1967
     * @return int
1968
     */
1969
    public function diffInHoursFiltered(Closure $callback, Date $dt = null, $abs = true)
1970
    {
1971
        return $this->diffFiltered(Interval::hour(), $callback, $dt, $abs);
1972
    }
1973
1974
    /**
1975
     * Get the difference by the given interval using a filter closure.
1976
     *
1977
     * @param Interval  $ci       An interval to traverse by
1978
     * @param Closure   $callback
1979
     * @param Date|null $dt
1980
     * @param bool      $abs      Get the absolute of the difference
1981
     *
1982
     * @return int
1983
     */
1984
    public function diffFiltered(Interval $ci, Closure $callback, Date $dt = null, $abs = true)
1985
    {
1986
        $start = $this;
1987
        $end = $dt ?: static::now($this->getTimezone());
1988
        $inverse = false;
1989
1990
        if ($end < $start) {
1991
            $start = $end;
1992
            $end = $this;
1993
            $inverse = true;
1994
        }
1995
1996
        $period = new DatePeriod($start, $ci, $end);
1997
        $vals = array_filter(
1998
            iterator_to_array($period),
1999
            function (DateTimeInterface $date) use ($callback) {
2000
                return call_user_func($callback, Date::instance($date));
2001
            }
2002
        );
2003
2004
        $diff = count($vals);
2005
2006
        return $inverse && !$abs ? -$diff : $diff;
2007
    }
2008
2009
    /**
2010
     * Get the difference in weekdays.
2011
     *
2012
     * @param Date|null $dt
2013
     * @param bool      $abs Get the absolute of the difference
2014
     *
2015
     * @return int
2016
     */
2017
    public function diffInWeekdays(Date $dt = null, $abs = true)
2018
    {
2019
        return $this->diffInDaysFiltered(
2020
            function (Date $date) {
2021
                return $date->isWeekday();
2022
            },
2023
            $dt,
2024
            $abs
2025
        );
2026
    }
2027
2028
    /**
2029
     * Get the difference in weekend days using a filter.
2030
     *
2031
     * @param Date|null $dt
2032
     * @param bool      $abs Get the absolute of the difference
2033
     *
2034
     * @return int
2035
     */
2036
    public function diffInWeekendDays(Date $dt = null, $abs = true)
2037
    {
2038
        return $this->diffInDaysFiltered(
2039
            function (Date $date) {
2040
                return $date->isWeekend();
2041
            },
2042
            $dt,
2043
            $abs
2044
        );
2045
    }
2046
2047
    /**
2048
     * Get the difference in hours.
2049
     *
2050
     * @param Date|null $dt
2051
     * @param bool      $abs Get the absolute of the difference
2052
     *
2053
     * @return int
2054
     */
2055
    public function diffInHours(Date $dt = null, $abs = true)
2056
    {
2057
        return (int) ($this->diffInSeconds($dt, $abs) / static::SECONDS_PER_MINUTE / static::MINUTES_PER_HOUR);
2058
    }
2059
2060
    /**
2061
     * Get the difference in minutes.
2062
     *
2063
     * @param Date|null $dt
2064
     * @param bool      $abs Get the absolute of the difference
2065
     *
2066
     * @return int
2067
     */
2068
    public function diffInMinutes(Date $dt = null, $abs = true)
2069
    {
2070
        return (int) ($this->diffInSeconds($dt, $abs) / static::SECONDS_PER_MINUTE);
2071
    }
2072
2073
    /**
2074
     * Get the difference in seconds.
2075
     *
2076
     * @param Date|null $dt
2077
     * @param bool      $abs Get the absolute of the difference
2078
     *
2079
     * @return int
2080
     */
2081
    public function diffInSeconds(Date $dt = null, $abs = true)
2082
    {
2083
        $dt = $dt ?: static::now($this->getTimezone());
2084
        $value = $dt->getTimestamp() - $this->getTimestamp();
2085
2086
        return $abs ? abs($value) : $value;
2087
    }
2088
2089
    /**
2090
     * The number of seconds since midnight.
2091
     *
2092
     * @return int
2093
     */
2094
    public function secondsSinceMidnight()
2095
    {
2096
        return $this->diffInSeconds($this->copy()->startOfDay());
2097
    }
2098
2099
    /**
2100
     * The number of seconds until 23:23:59.
2101
     *
2102
     * @return int
2103
     */
2104
    public function secondsUntilEndOfDay()
2105
    {
2106
        return $this->diffInSeconds($this->copy()->endOfDay());
2107
    }
2108
2109
    /**
2110
     * Get the difference in a human readable format in the current locale.
2111
     *
2112
     * When comparing a value in the past to default now:
2113
     * 1 hour ago
2114
     * 5 months ago
2115
     *
2116
     * When comparing a value in the future to default now:
2117
     * 1 hour from now
2118
     * 5 months from now
2119
     *
2120
     * When comparing a value in the past to another value:
2121
     * 1 hour before
2122
     * 5 months before
2123
     *
2124
     * When comparing a value in the future to another value:
2125
     * 1 hour after
2126
     * 5 months after
2127
     *
2128
     * @param Date|null $other
2129
     * @param bool      $absolute removes time difference modifiers ago, after, etc
2130
     *
2131
     * @return string
2132
     */
2133
    public function diffForHumans(Date $other = null, $absolute = false)
2134
    {
2135
        $isNow = $other === null;
2136
2137
        if ($isNow) {
2138
            $other = static::now($this->getTimezone());
2139
        }
2140
2141
        $diffInterval = $this->diff($other);
2142
2143
        switch (true) {
2144
            case ($diffInterval->y > 0):
2145
                $unit = 'year';
2146
                $count = $diffInterval->y;
2147
                break;
2148
2149
            case ($diffInterval->m > 0):
2150
                $unit = 'month';
2151
                $count = $diffInterval->m;
2152
                break;
2153
2154
            case ($diffInterval->d > 0):
2155
                $unit = 'day';
2156
                $count = $diffInterval->d;
2157
                if ($count >= self::DAYS_PER_WEEK) {
2158
                    $unit = 'week';
2159
                    $count = (int) ($count / self::DAYS_PER_WEEK);
2160
                }
2161
                break;
2162
2163
            case ($diffInterval->h > 0):
2164
                $unit = 'hour';
2165
                $count = $diffInterval->h;
2166
                break;
2167
2168
            case ($diffInterval->i > 0):
2169
                $unit = 'minute';
2170
                $count = $diffInterval->i;
2171
                break;
2172
2173
            default:
2174
                $count = $diffInterval->s;
2175
                $unit = 'second';
2176
                break;
2177
        }
2178
2179
        if ($count === 0) {
2180
            $count = 1;
2181
        }
2182
2183
        $time = static::translator()->transChoice($unit, $count, [':count' => $count]);
2184
2185
        if ($absolute) {
2186
            return $time;
2187
        }
2188
2189
        $isFuture = $diffInterval->invert === 1;
2190
2191
        $transId = $isNow ? ($isFuture ? 'from_now' : 'ago') : ($isFuture ? 'after' : 'before');
2192
2193
        // Some langs have special pluralization for past and future tense.
2194
        $tryKeyExists = $unit.'_'.$transId;
2195
        if ($tryKeyExists !== static::translator()->transChoice($tryKeyExists, $count)) {
2196
            $time = static::translator()->transChoice($tryKeyExists, $count, [':count' => $count]);
2197
        }
2198
2199
        return static::translator()->trans($transId, [':time' => $time]);
2200
    }
2201
2202
    ///////////////////////////////////////////////////////////////////
2203
    //////////////////////////// MODIFIERS ////////////////////////////
2204
    ///////////////////////////////////////////////////////////////////
2205
2206
    /**
2207
     * Resets the time to 00:00:00.
2208
     *
2209
     * @return static
2210
     */
2211
    public function startOfDay()
2212
    {
2213
        return $this->hour(0)->minute(0)->second(0);
2214
    }
2215
2216
    /**
2217
     * Resets the time to 23:59:59.
2218
     *
2219
     * @return static
2220
     */
2221
    public function endOfDay()
2222
    {
2223
        return $this->hour(23)->minute(59)->second(59);
2224
    }
2225
2226
    /**
2227
     * Resets the date to the first day of the month and the time to 00:00:00.
2228
     *
2229
     * @return static
2230
     */
2231
    public function startOfMonth()
2232
    {
2233
        return $this->startOfDay()->day(1);
2234
    }
2235
2236
    /**
2237
     * Resets the date to end of the month and time to 23:59:59.
2238
     *
2239
     * @return static
2240
     */
2241
    public function endOfMonth()
2242
    {
2243
        return $this->day($this->getDaysInMonth())->endOfDay();
2244
    }
2245
2246
    /**
2247
     * Resets the date to the first day of the year and the time to 00:00:00.
2248
     *
2249
     * @return static
2250
     */
2251
    public function startOfYear()
2252
    {
2253
        return $this->month(1)->startOfMonth();
2254
    }
2255
2256
    /**
2257
     * Resets the date to end of the year and time to 23:59:59.
2258
     *
2259
     * @return static
2260
     */
2261
    public function endOfYear()
2262
    {
2263
        return $this->month(static::MONTHS_PER_YEAR)->endOfMonth();
2264
    }
2265
2266
    /**
2267
     * Resets the date to the first day of the decade and the time to 00:00:00.
2268
     *
2269
     * @return static
2270
     */
2271
    public function startOfDecade()
2272
    {
2273
        return $this->startOfYear()->year($this->getYear() - $this->getYear() % static::YEARS_PER_DECADE);
2274
    }
2275
2276
    /**
2277
     * Resets the date to end of the decade and time to 23:59:59.
2278
     *
2279
     * @return static
2280
     */
2281
    public function endOfDecade()
2282
    {
2283
        return $this->endOfYear()->year(
2284
            $this->getYear() - $this->getYear() % static::YEARS_PER_DECADE + static::YEARS_PER_DECADE - 1
2285
        );
2286
    }
2287
2288
    /**
2289
     * Resets the date to the first day of the century and the time to 00:00:00.
2290
     *
2291
     * @return static
2292
     */
2293
    public function startOfCentury()
2294
    {
2295
        return $this->startOfYear()->year($this->getYear() - $this->getYear() % static::YEARS_PER_CENTURY);
2296
    }
2297
2298
    /**
2299
     * Resets the date to end of the century and time to 23:59:59.
2300
     *
2301
     * @return static
2302
     */
2303
    public function endOfCentury()
2304
    {
2305
        return $this->endOfYear()->year(
2306
            $this->getYear() - $this->getYear() % static::YEARS_PER_CENTURY + static::YEARS_PER_CENTURY - 1
2307
        );
2308
    }
2309
2310
    /**
2311
     * Resets the date to the first day of week (defined in $weekStartsAt) and the time to 00:00:00.
2312
     *
2313
     * @return static
2314
     */
2315
    public function startOfWeek()
2316
    {
2317
        if ($this->getDayOfWeek() !== static::$weekStartsAt) {
2318
            return $this->previous(static::$weekStartsAt);
2319
        }
2320
2321
        return $this->startOfDay();
2322
    }
2323
2324
    /**
2325
     * Resets the date to end of week (defined in $weekEndsAt) and time to 23:59:59.
2326
     *
2327
     * @return static
2328
     */
2329
    public function endOfWeek()
2330
    {
2331
        if ($this->getDayOfWeek() !== static::$weekEndsAt) {
2332
            return $this->next(static::$weekEndsAt)->endOfDay();
2333
        }
2334
2335
        return $this->endOfDay();
2336
    }
2337
2338
    /**
2339
     * Modify to the next occurrence of a given day of the week.
2340
     * If no dayOfWeek is provided, modify to the next occurrence
2341
     * of the current day of the week.  Use the supplied consts
2342
     * to indicate the desired dayOfWeek, ex. static::MONDAY.
2343
     *
2344
     * @param int|null $dayOfWeek
2345
     *
2346
     * @return static
2347
     */
2348 View Code Duplication
    public function next($dayOfWeek = null)
0 ignored issues
show
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...
2349
    {
2350
        if ($dayOfWeek === null) {
2351
            $dayOfWeek = $this->getDayOfWeek();
2352
        }
2353
2354
        return $this->startOfDay()->modify('next '.static::$days[$dayOfWeek]);
2355
    }
2356
2357
    /**
2358
     * Modify to the previous occurrence of a given day of the week.
2359
     * If no dayOfWeek is provided, modify to the previous occurrence
2360
     * of the current day of the week.  Use the supplied consts
2361
     * to indicate the desired dayOfWeek, ex. static::MONDAY.
2362
     *
2363
     * @param int|null $dayOfWeek
2364
     *
2365
     * @return static
2366
     */
2367 View Code Duplication
    public function previous($dayOfWeek = null)
0 ignored issues
show
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...
2368
    {
2369
        if ($dayOfWeek === null) {
2370
            $dayOfWeek = $this->getDayOfWeek();
2371
        }
2372
2373
        return $this->startOfDay()->modify('last '.static::$days[$dayOfWeek]);
2374
    }
2375
2376
    /**
2377
     * Modify to the first occurrence of a given day of the week
2378
     * in the current month. If no dayOfWeek is provided, modify to the
2379
     * first day of the current month.  Use the supplied consts
2380
     * to indicate the desired dayOfWeek, ex. static::MONDAY.
2381
     *
2382
     * @param int|null $dayOfWeek
2383
     *
2384
     * @return static
2385
     */
2386 View Code Duplication
    public function firstOfMonth($dayOfWeek = null)
0 ignored issues
show
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...
2387
    {
2388
        $date = $this->startOfDay();
2389
2390
        if ($dayOfWeek === null) {
2391
            return $date->day(1);
2392
        }
2393
2394
        return $this->modify('first '.static::$days[$dayOfWeek].' of '.$this->format('F').' '.$this->getYear());
2395
    }
2396
2397
    /**
2398
     * Modify to the last occurrence of a given day of the week
2399
     * in the current month. If no dayOfWeek is provided, modify to the
2400
     * last day of the current month.  Use the supplied consts
2401
     * to indicate the desired dayOfWeek, ex. static::MONDAY.
2402
     *
2403
     * @param int|null $dayOfWeek
2404
     *
2405
     * @return static
2406
     */
2407 View Code Duplication
    public function lastOfMonth($dayOfWeek = null)
0 ignored issues
show
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...
2408
    {
2409
        $date = $this->startOfDay();
2410
2411
        if ($dayOfWeek === null) {
2412
            return $date->day($this->getDaysInMonth());
2413
        }
2414
2415
        return $this->modify('last '.static::$days[$dayOfWeek].' of '.$this->format('F').' '.$this->getYear());
2416
    }
2417
2418
    /**
2419
     * Modify to the given occurrence of a given day of the week
2420
     * in the current month. If the calculated occurrence is outside the scope
2421
     * of the current month, then return false and no modifications are made.
2422
     * Use the supplied consts to indicate the desired dayOfWeek, ex. static::MONDAY.
2423
     *
2424
     * @param int $nth
2425
     * @param int $dayOfWeek
2426
     *
2427
     * @return mixed
2428
     */
2429
    public function nthOfMonth($nth, $dayOfWeek)
2430
    {
2431
        $dt = $this->copy()->firstOfMonth();
2432
        $check = $dt->format('Y-m');
2433
        $dt = $dt->modify('+'.$nth.' '.static::$days[$dayOfWeek]);
2434
2435
        return $dt->format('Y-m') === $check ? $this->modify((string) $dt) : false;
2436
    }
2437
2438
    /**
2439
     * Modify to the first occurrence of a given day of the week
2440
     * in the current quarter. If no dayOfWeek is provided, modify to the
2441
     * first day of the current quarter.  Use the supplied consts
2442
     * to indicate the desired dayOfWeek, ex. static::MONDAY.
2443
     *
2444
     * @param int|null $dayOfWeek
2445
     *
2446
     * @return static
2447
     */
2448
    public function firstOfQuarter($dayOfWeek = null)
2449
    {
2450
        return $this->day(1)->month($this->getQuarter() * 3 - 2)->firstOfMonth($dayOfWeek);
2451
    }
2452
2453
    /**
2454
     * Modify to the last occurrence of a given day of the week
2455
     * in the current quarter. If no dayOfWeek is provided, modify to the
2456
     * last day of the current quarter.  Use the supplied consts
2457
     * to indicate the desired dayOfWeek, ex. static::MONDAY.
2458
     *
2459
     * @param int|null $dayOfWeek
2460
     *
2461
     * @return static
2462
     */
2463
    public function lastOfQuarter($dayOfWeek = null)
2464
    {
2465
        return $this->day(1)->month($this->getQuarter() * 3)->lastOfMonth($dayOfWeek);
2466
    }
2467
2468
    /**
2469
     * Modify to the given occurrence of a given day of the week
2470
     * in the current quarter. If the calculated occurrence is outside the scope
2471
     * of the current quarter, then return false and no modifications are made.
2472
     * Use the supplied consts to indicate the desired dayOfWeek, ex. static::MONDAY.
2473
     *
2474
     * @param int $nth
2475
     * @param int $dayOfWeek
2476
     *
2477
     * @return Date|bool
2478
     */
2479
    public function nthOfQuarter($nth, $dayOfWeek)
2480
    {
2481
        $dt = $this->day(1)->month($this->getQuarter() * 3);
2482
        $lastMonth = $dt->getMonth();
2483
        $year = $dt->getYear();
2484
        $dt = $dt->firstOfQuarter()->modify('+'.$nth.' '.static::$days[$dayOfWeek]);
2485
2486
        return ($lastMonth < $dt->getMonth() || $year !== $dt->getYear()) ? false : $this->modify((string) $dt);
2487
    }
2488
2489
    /**
2490
     * Modify to the first occurrence of a given day of the week
2491
     * in the current year. If no dayOfWeek is provided, modify to the
2492
     * first day of the current year.  Use the supplied consts
2493
     * to indicate the desired dayOfWeek, ex. static::MONDAY.
2494
     *
2495
     * @param int|null $dayOfWeek
2496
     *
2497
     * @return static
2498
     */
2499
    public function firstOfYear($dayOfWeek = null)
2500
    {
2501
        return $this->month(1)->firstOfMonth($dayOfWeek);
2502
    }
2503
2504
    /**
2505
     * Modify to the last occurrence of a given day of the week
2506
     * in the current year. If no dayOfWeek is provided, modify to the
2507
     * last day of the current year.  Use the supplied consts
2508
     * to indicate the desired dayOfWeek, ex. static::MONDAY.
2509
     *
2510
     * @param int|null $dayOfWeek
2511
     *
2512
     * @return static
2513
     */
2514
    public function lastOfYear($dayOfWeek = null)
2515
    {
2516
        return $this->month(static::MONTHS_PER_YEAR)->lastOfMonth($dayOfWeek);
2517
    }
2518
2519
    /**
2520
     * Modify to the given occurrence of a given day of the week
2521
     * in the current year. If the calculated occurrence is outside the scope
2522
     * of the current year, then return false and no modifications are made.
2523
     * Use the supplied consts to indicate the desired dayOfWeek, ex. static::MONDAY.
2524
     *
2525
     * @param int $nth
2526
     * @param int $dayOfWeek
2527
     *
2528
     * @return mixed
2529
     */
2530
    public function nthOfYear($nth, $dayOfWeek)
2531
    {
2532
        $dt = $this->copy()->firstOfYear()->modify('+'.$nth.' '.static::$days[$dayOfWeek]);
2533
2534
        return $this->getYear() === $dt->getYear() ? $this->modify((string) $dt) : false;
2535
    }
2536
2537
    /**
2538
     * Modify the current instance to the average of a given instance (default now) and the current instance.
2539
     *
2540
     * @param Date|null $dt
2541
     *
2542
     * @return static
2543
     */
2544
    public function average(Date $dt = null)
2545
    {
2546
        $dt = $dt ?: static::now($this->getTimezone());
2547
2548
        return $this->addSeconds((int) ($this->diffInSeconds($dt, false) / 2));
2549
    }
2550
2551
    /**
2552
     * Check if its the birthday. Compares the date/month values of the two dates.
2553
     *
2554
     * @param Date|null $dt The instance to compare with or null to use current day.
2555
     *
2556
     * @return bool
2557
     */
2558
    public function isBirthday(Date $dt = null)
2559
    {
2560
        $dt = $dt ?: static::now($this->getTimezone());
2561
2562
        return $this->format('md') === $dt->format('md');
2563
    }
2564
2565
    /**
2566
     *   Alters the timestamp.
2567
     *
2568
     * @param string $value
2569
     *
2570
     * @return static
2571
     */
2572
    public function modify($value)
2573
    {
2574
        return parent::modify($value);
2575
    }
2576
}
2577