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

15
/**
16
 * Trait Modifiers.
17
 *
18
 * Returns dates relative to current date using modifier short-hand.
19
 */
20
trait Modifiers
21
{
22
    /**
23
     * Midday/noon hour.
24
     *
25
     * @var int
26
     */
27
    protected static $midDayAt = 12;
28

29
    /**
30
     * get midday/noon hour
31
     *
32
     * @return int
33
     */
34 1
    public static function getMidDayAt()
35
    {
36 1
        return static::$midDayAt;
37
    }
38

39
    /**
40
     * @deprecated To avoid conflict between different third-party libraries, static setters should not be used.
41
     *             You should rather consider mid-day is always 12pm, then if you need to test if it's an other
42
     *             hour, test it explicitly:
43
     *                 $date->format('G') == 13
44
     *             or to set explicitly to a given hour:
45
     *                 $date->setTime(13, 0, 0, 0)
46
     *
47
     * Set midday/noon hour
48
     *
49
     * @param int $hour midday hour
50
     *
51
     * @return void
52
     */
53 1
    public static function setMidDayAt($hour)
54
    {
55 1
        static::$midDayAt = $hour;
56
    }
57

58
    /**
59
     * Modify to midday, default to self::$midDayAt
60
     *
61
     * @return static
62
     */
63 1
    public function midDay()
64
    {
65 1
        return $this->setTime(static::$midDayAt, 0, 0, 0);
66
    }
67

68
    /**
69
     * Modify to the next occurrence of a given modifier such as a day of
70
     * the week. If no modifier is provided, modify to the next occurrence
71
     * of the current day of the week. Use the supplied constants
72
     * to indicate the desired dayOfWeek, ex. static::MONDAY.
73
     *
74
     * @param string|int|null $modifier
75
     *
76
     * @return static
77
     */
78 1
    public function next($modifier = null)
79
    {
80 1
        if ($modifier === null) {
81 1
            $modifier = $this->dayOfWeek;
82
        }
83

84 1
        return $this->change(
85 1
            'next '.(\is_string($modifier) ? $modifier : static::$days[$modifier])
86
        );
87
    }
88

89
    /**
90
     * Go forward or backward to the next week- or weekend-day.
91
     *
92
     * @param bool $weekday
93
     * @param bool $forward
94
     *
95
     * @return static
96
     */
97 1
    private function nextOrPreviousDay($weekday = true, $forward = true)
98
    {
99
        /** @var CarbonInterface $date */
100 1
        $date = $this;
101 1
        $step = $forward ? 1 : -1;
102

103
        do {
104 1
            $date = $date->addDays($step);
105 1
        } while ($weekday ? $date->isWeekend() : $date->isWeekday());
106

107 1
        return $date;
108
    }
109

110
    /**
111
     * Go forward to the next weekday.
112
     *
113
     * @return static
114
     */
115 1
    public function nextWeekday()
116
    {
117 1
        return $this->nextOrPreviousDay();
118
    }
119

120
    /**
121
     * Go backward to the previous weekday.
122
     *
123
     * @return static
124
     */
125 1
    public function previousWeekday()
126
    {
127 1
        return $this->nextOrPreviousDay(true, false);
128
    }
129

130
    /**
131
     * Go forward to the next weekend day.
132
     *
133
     * @return static
134
     */
135 1
    public function nextWeekendDay()
136
    {
137 1
        return $this->nextOrPreviousDay(false);
138
    }
139

140
    /**
141
     * Go backward to the previous weekend day.
142
     *
143
     * @return static
144
     */
145 1
    public function previousWeekendDay()
146
    {
147 1
        return $this->nextOrPreviousDay(false, false);
148
    }
149

150
    /**
151
     * Modify to the previous occurrence of a given modifier such as a day of
152
     * the week. If no dayOfWeek is provided, modify to the previous occurrence
153
     * of the current day of the week. Use the supplied constants
154
     * to indicate the desired dayOfWeek, ex. static::MONDAY.
155
     *
156
     * @param string|int|null $modifier
157
     *
158
     * @return static
159
     */
160 1
    public function previous($modifier = null)
161
    {
162 1
        if ($modifier === null) {
163 1
            $modifier = $this->dayOfWeek;
164
        }
165

166 1
        return $this->change(
167 1
            'last '.(\is_string($modifier) ? $modifier : static::$days[$modifier])
168
        );
169
    }
170

171
    /**
172
     * Modify to the first occurrence of a given day of the week
173
     * in the current month. If no dayOfWeek is provided, modify to the
174
     * first day of the current month.  Use the supplied constants
175
     * to indicate the desired dayOfWeek, ex. static::MONDAY.
176
     *
177
     * @param int|null $dayOfWeek
178
     *
179
     * @return static
180
     */
181 1
    public function firstOfMonth($dayOfWeek = null)
182
    {
183 1
        $date = $this->startOfDay();
184

185 1
        if ($dayOfWeek === null) {
186 1
            return $date->day(1);
187
        }
188

189 1
        return $date->modify('first '.static::$days[$dayOfWeek].' of '.$date->rawFormat('F').' '.$date->year);
190
    }
191

192
    /**
193
     * Modify to the last occurrence of a given day of the week
194
     * in the current month. If no dayOfWeek is provided, modify to the
195
     * last day of the current month.  Use the supplied constants
196
     * to indicate the desired dayOfWeek, ex. static::MONDAY.
197
     *
198
     * @param int|null $dayOfWeek
199
     *
200
     * @return static
201
     */
202 1
    public function lastOfMonth($dayOfWeek = null)
203
    {
204 1
        $date = $this->startOfDay();
205

206 1
        if ($dayOfWeek === null) {
207 1
            return $date->day($date->daysInMonth);
208
        }
209

210 1
        return $date->modify('last '.static::$days[$dayOfWeek].' of '.$date->rawFormat('F').' '.$date->year);
211
    }
212

213
    /**
214
     * Modify to the given occurrence of a given day of the week
215
     * in the current month. If the calculated occurrence is outside the scope
216
     * of the current month, then return false and no modifications are made.
217
     * Use the supplied constants to indicate the desired dayOfWeek, ex. static::MONDAY.
218
     *
219
     * @param int $nth
220
     * @param int $dayOfWeek
221
     *
222
     * @return mixed
223
     */
224 1
    public function nthOfMonth($nth, $dayOfWeek)
225
    {
226 1
        $date = $this->copy()->firstOfMonth();
227 1
        $check = $date->rawFormat('Y-m');
228 1
        $date = $date->modify('+'.$nth.' '.static::$days[$dayOfWeek]);
229

230 1
        return $date->rawFormat('Y-m') === $check ? $this->modify("$date") : false;
231
    }
232

233
    /**
234
     * Modify to the first occurrence of a given day of the week
235
     * in the current quarter. If no dayOfWeek is provided, modify to the
236
     * first day of the current quarter.  Use the supplied constants
237
     * to indicate the desired dayOfWeek, ex. static::MONDAY.
238
     *
239
     * @param int|null $dayOfWeek day of the week default null
240
     *
241
     * @return static
242
     */
243 1
    public function firstOfQuarter($dayOfWeek = null)
244
    {
245 1
        return $this->setDate($this->year, $this->quarter * static::MONTHS_PER_QUARTER - 2, 1)->firstOfMonth($dayOfWeek);
246
    }
247

248
    /**
249
     * Modify to the last occurrence of a given day of the week
250
     * in the current quarter. If no dayOfWeek is provided, modify to the
251
     * last day of the current quarter.  Use the supplied constants
252
     * to indicate the desired dayOfWeek, ex. static::MONDAY.
253
     *
254
     * @param int|null $dayOfWeek day of the week default null
255
     *
256
     * @return static
257
     */
258 1
    public function lastOfQuarter($dayOfWeek = null)
259
    {
260 1
        return $this->setDate($this->year, $this->quarter * static::MONTHS_PER_QUARTER, 1)->lastOfMonth($dayOfWeek);
261
    }
262

263
    /**
264
     * Modify to the given occurrence of a given day of the week
265
     * in the current quarter. If the calculated occurrence is outside the scope
266
     * of the current quarter, then return false and no modifications are made.
267
     * Use the supplied constants to indicate the desired dayOfWeek, ex. static::MONDAY.
268
     *
269
     * @param int $nth
270
     * @param int $dayOfWeek
271
     *
272
     * @return mixed
273
     */
274 1
    public function nthOfQuarter($nth, $dayOfWeek)
275
    {
276 1
        $date = $this->copy()->day(1)->month($this->quarter * static::MONTHS_PER_QUARTER);
277 1
        $lastMonth = $date->month;
278 1
        $year = $date->year;
279 1
        $date = $date->firstOfQuarter()->modify('+'.$nth.' '.static::$days[$dayOfWeek]);
280

281 1
        return ($lastMonth < $date->month || $year !== $date->year) ? false : $this->modify("$date");
282
    }
283

284
    /**
285
     * Modify to the first occurrence of a given day of the week
286
     * in the current year. If no dayOfWeek is provided, modify to the
287
     * first day of the current year.  Use the supplied constants
288
     * to indicate the desired dayOfWeek, ex. static::MONDAY.
289
     *
290
     * @param int|null $dayOfWeek day of the week default null
291
     *
292
     * @return static
293
     */
294 1
    public function firstOfYear($dayOfWeek = null)
295
    {
296 1
        return $this->month(1)->firstOfMonth($dayOfWeek);
297
    }
298

299
    /**
300
     * Modify to the last occurrence of a given day of the week
301
     * in the current year. If no dayOfWeek is provided, modify to the
302
     * last day of the current year.  Use the supplied constants
303
     * to indicate the desired dayOfWeek, ex. static::MONDAY.
304
     *
305
     * @param int|null $dayOfWeek day of the week default null
306
     *
307
     * @return static
308
     */
309 1
    public function lastOfYear($dayOfWeek = null)
310
    {
311 1
        return $this->month(static::MONTHS_PER_YEAR)->lastOfMonth($dayOfWeek);
312
    }
313

314
    /**
315
     * Modify to the given occurrence of a given day of the week
316
     * in the current year. If the calculated occurrence is outside the scope
317
     * of the current year, then return false and no modifications are made.
318
     * Use the supplied constants to indicate the desired dayOfWeek, ex. static::MONDAY.
319
     *
320
     * @param int $nth
321
     * @param int $dayOfWeek
322
     *
323
     * @return mixed
324
     */
325 1
    public function nthOfYear($nth, $dayOfWeek)
326
    {
327 1
        $date = $this->copy()->firstOfYear()->modify('+'.$nth.' '.static::$days[$dayOfWeek]);
328

329 1
        return $this->year === $date->year ? $this->modify("$date") : false;
330
    }
331

332
    /**
333
     * Modify the current instance to the average of a given instance (default now) and the current instance
334
     * (second-precision).
335
     *
336
     * @param \Carbon\Carbon|\DateTimeInterface|null $date
337
     *
338
     * @return static
339
     */
340 1
    public function average($date = null)
341
    {
342 1
        return $this->addRealMicroseconds((int) ($this->diffInRealMicroseconds($this->resolveCarbon($date), false) / 2));
343
    }
344

345
    /**
346
     * Get the closest date from the instance (second-precision).
347
     *
348
     * @param \Carbon\Carbon|\DateTimeInterface|mixed $date1
349
     * @param \Carbon\Carbon|\DateTimeInterface|mixed $date2
350
     *
351
     * @return static
352
     */
353 1
    public function closest($date1, $date2)
354
    {
355 1
        return $this->diffInRealMicroseconds($date1) < $this->diffInRealMicroseconds($date2) ? $date1 : $date2;
356
    }
357

358
    /**
359
     * Get the farthest date from the instance (second-precision).
360
     *
361
     * @param \Carbon\Carbon|\DateTimeInterface|mixed $date1
362
     * @param \Carbon\Carbon|\DateTimeInterface|mixed $date2
363
     *
364
     * @return static
365
     */
366 1
    public function farthest($date1, $date2)
367
    {
368 1
        return $this->diffInRealMicroseconds($date1) > $this->diffInRealMicroseconds($date2) ? $date1 : $date2;
369
    }
370

371
    /**
372
     * Get the minimum instance between a given instance (default now) and the current instance.
373
     *
374
     * @param \Carbon\Carbon|\DateTimeInterface|mixed $date
375
     *
376
     * @return static
377
     */
378 1
    public function min($date = null)
379
    {
380 1
        $date = $this->resolveCarbon($date);
381

382 1
        return $this->lt($date) ? $this : $date;
383
    }
384

385
    /**
386
     * Get the minimum instance between a given instance (default now) and the current instance.
387
     *
388
     * @param \Carbon\Carbon|\DateTimeInterface|mixed $date
389
     *
390
     * @see min()
391
     *
392
     * @return static
393
     */
394 1
    public function minimum($date = null)
395
    {
396 1
        return $this->min($date);
397
    }
398

399
    /**
400
     * Get the maximum instance between a given instance (default now) and the current instance.
401
     *
402
     * @param \Carbon\Carbon|\DateTimeInterface|mixed $date
403
     *
404
     * @return static
405
     */
406 1
    public function max($date = null)
407
    {
408 1
        $date = $this->resolveCarbon($date);
409

410 1
        return $this->gt($date) ? $this : $date;
411
    }
412

413
    /**
414
     * Get the maximum instance between a given instance (default now) and the current instance.
415
     *
416
     * @param \Carbon\Carbon|\DateTimeInterface|mixed $date
417
     *
418
     * @see max()
419
     *
420
     * @return static
421
     */
422 1
    public function maximum($date = null)
423
    {
424 1
        return $this->max($date);
425
    }
426

427
    /**
428
     * Calls \DateTime::modify if mutable or \DateTimeImmutable::modify else.
429
     *
430
     * @see https://php.net/manual/en/datetime.modify.php
431
     */
432 1
    public function modify($modify)
433
    {
434 1
        return parent::modify((string) $modify);
435
    }
436

437
    /**
438
     * Similar to native modify() method of DateTime but can handle more grammars.
439
     *
440
     * @example
441
     * ```
442
     * echo Carbon::now()->change('next 2pm');
443
     * ```
444
     *
445
     * @link https://php.net/manual/en/datetime.modify.php
446
     *
447
     * @param string $modifier
448
     *
449
     * @return static
450
     */
451 1
    public function change($modifier)
452
    {
453
        return $this->modify(preg_replace_callback('/^(next|previous|last)\s+(\d{1,2}(h|am|pm|:\d{1,2}(:\d{1,2})?))$/i', function ($match) {
454 1
            $match[2] = str_replace('h', ':00', $match[2]);
455 1
            $test = $this->copy()->modify($match[2]);
456 1
            $method = $match[1] === 'next' ? 'lt' : 'gt';
457 1
            $match[1] = $test->$method($this) ? $match[1].' day' : 'today';
458

459 1
            return $match[1].' '.$match[2];
460 1
        }, strtr(trim($modifier), [
461 1
            ' at ' => ' ',
462
            'just now' => 'now',
463
            'after tomorrow' => 'tomorrow +1 day',
464
            'before yesterday' => 'yesterday -1 day',
465
        ])));
466
    }
467
}

Read our documentation on viewing source code .

Loading