Subversion-Projekte lars-tiefland.laravel_shop

Revision

Details | Letzte Änderung | Log anzeigen | RSS feed

Revision Autor Zeilennr. Zeile
148 lars 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
 
12
namespace Carbon\Traits;
13
 
14
use Carbon\CarbonConverterInterface;
15
use Carbon\CarbonInterface;
16
use Carbon\CarbonInterval;
17
use Carbon\Exceptions\UnitException;
18
use Closure;
19
use DateInterval;
20
use ReturnTypeWillChange;
21
 
22
/**
23
 * Trait Units.
24
 *
25
 * Add, subtract and set units.
26
 */
27
trait Units
28
{
29
    /**
30
     * Add seconds to the instance using timestamp. Positive $value travels
31
     * forward while negative $value travels into the past.
32
     *
33
     * @param string $unit
34
     * @param int    $value
35
     *
36
     * @return static
37
     */
38
    public function addRealUnit($unit, $value = 1)
39
    {
40
        switch ($unit) {
41
            // @call addRealUnit
42
            case 'micro':
43
 
44
            // @call addRealUnit
45
            case 'microsecond':
46
                /* @var CarbonInterface $this */
47
                $diff = $this->microsecond + $value;
48
                $time = $this->getTimestamp();
49
                $seconds = (int) floor($diff / static::MICROSECONDS_PER_SECOND);
50
                $time += $seconds;
51
                $diff -= $seconds * static::MICROSECONDS_PER_SECOND;
52
                $microtime = str_pad((string) $diff, 6, '0', STR_PAD_LEFT);
53
                $tz = $this->tz;
54
 
55
                return $this->tz('UTC')->modify("@$time.$microtime")->tz($tz);
56
 
57
            // @call addRealUnit
58
            case 'milli':
59
            // @call addRealUnit
60
            case 'millisecond':
61
                return $this->addRealUnit('microsecond', $value * static::MICROSECONDS_PER_MILLISECOND);
62
 
63
            // @call addRealUnit
64
            case 'second':
65
                break;
66
 
67
            // @call addRealUnit
68
            case 'minute':
69
                $value *= static::SECONDS_PER_MINUTE;
70
 
71
                break;
72
 
73
            // @call addRealUnit
74
            case 'hour':
75
                $value *= static::MINUTES_PER_HOUR * static::SECONDS_PER_MINUTE;
76
 
77
                break;
78
 
79
            // @call addRealUnit
80
            case 'day':
81
                $value *= static::HOURS_PER_DAY * static::MINUTES_PER_HOUR * static::SECONDS_PER_MINUTE;
82
 
83
                break;
84
 
85
            // @call addRealUnit
86
            case 'week':
87
                $value *= static::DAYS_PER_WEEK * static::HOURS_PER_DAY * static::MINUTES_PER_HOUR * static::SECONDS_PER_MINUTE;
88
 
89
                break;
90
 
91
            // @call addRealUnit
92
            case 'month':
93
                $value *= 30 * static::HOURS_PER_DAY * static::MINUTES_PER_HOUR * static::SECONDS_PER_MINUTE;
94
 
95
                break;
96
 
97
            // @call addRealUnit
98
            case 'quarter':
99
                $value *= static::MONTHS_PER_QUARTER * 30 * static::HOURS_PER_DAY * static::MINUTES_PER_HOUR * static::SECONDS_PER_MINUTE;
100
 
101
                break;
102
 
103
            // @call addRealUnit
104
            case 'year':
105
                $value *= 365 * static::HOURS_PER_DAY * static::MINUTES_PER_HOUR * static::SECONDS_PER_MINUTE;
106
 
107
                break;
108
 
109
            // @call addRealUnit
110
            case 'decade':
111
                $value *= static::YEARS_PER_DECADE * 365 * static::HOURS_PER_DAY * static::MINUTES_PER_HOUR * static::SECONDS_PER_MINUTE;
112
 
113
                break;
114
 
115
            // @call addRealUnit
116
            case 'century':
117
                $value *= static::YEARS_PER_CENTURY * 365 * static::HOURS_PER_DAY * static::MINUTES_PER_HOUR * static::SECONDS_PER_MINUTE;
118
 
119
                break;
120
 
121
            // @call addRealUnit
122
            case 'millennium':
123
                $value *= static::YEARS_PER_MILLENNIUM * 365 * static::HOURS_PER_DAY * static::MINUTES_PER_HOUR * static::SECONDS_PER_MINUTE;
124
 
125
                break;
126
 
127
            default:
128
                if ($this->localStrictModeEnabled ?? static::isStrictModeEnabled()) {
129
                    throw new UnitException("Invalid unit for real timestamp add/sub: '$unit'");
130
                }
131
 
132
                return $this;
133
        }
134
 
135
        /* @var CarbonInterface $this */
136
        return $this->setTimestamp((int) ($this->getTimestamp() + $value));
137
    }
138
 
139
    public function subRealUnit($unit, $value = 1)
140
    {
141
        return $this->addRealUnit($unit, -$value);
142
    }
143
 
144
    /**
145
     * Returns true if a property can be changed via setter.
146
     *
147
     * @param string $unit
148
     *
149
     * @return bool
150
     */
151
    public static function isModifiableUnit($unit)
152
    {
153
        static $modifiableUnits = [
154
            // @call addUnit
155
            'millennium',
156
            // @call addUnit
157
            'century',
158
            // @call addUnit
159
            'decade',
160
            // @call addUnit
161
            'quarter',
162
            // @call addUnit
163
            'week',
164
            // @call addUnit
165
            'weekday',
166
        ];
167
 
168
        return \in_array($unit, $modifiableUnits, true) || \in_array($unit, static::$units, true);
169
    }
170
 
171
    /**
172
     * Call native PHP DateTime/DateTimeImmutable add() method.
173
     *
174
     * @param DateInterval $interval
175
     *
176
     * @return static
177
     */
178
    public function rawAdd(DateInterval $interval)
179
    {
180
        return parent::add($interval);
181
    }
182
 
183
    /**
184
     * Add given units or interval to the current instance.
185
     *
186
     * @example $date->add('hour', 3)
187
     * @example $date->add(15, 'days')
188
     * @example $date->add(CarbonInterval::days(4))
189
     *
190
     * @param string|DateInterval|Closure|CarbonConverterInterface $unit
191
     * @param int                                                  $value
192
     * @param bool|null                                            $overflow
193
     *
194
     * @return static
195
     */
196
    #[ReturnTypeWillChange]
197
    public function add($unit, $value = 1, $overflow = null)
198
    {
199
        if (\is_string($unit) && \func_num_args() === 1) {
200
            $unit = CarbonInterval::make($unit);
201
        }
202
 
203
        if ($unit instanceof CarbonConverterInterface) {
204
            return $this->resolveCarbon($unit->convertDate($this, false));
205
        }
206
 
207
        if ($unit instanceof Closure) {
208
            return $this->resolveCarbon($unit($this, false));
209
        }
210
 
211
        if ($unit instanceof DateInterval) {
212
            return parent::add($unit);
213
        }
214
 
215
        if (is_numeric($unit)) {
216
            [$value, $unit] = [$unit, $value];
217
        }
218
 
219
        return $this->addUnit($unit, $value, $overflow);
220
    }
221
 
222
    /**
223
     * Add given units to the current instance.
224
     *
225
     * @param string    $unit
226
     * @param int       $value
227
     * @param bool|null $overflow
228
     *
229
     * @return static
230
     */
231
    public function addUnit($unit, $value = 1, $overflow = null)
232
    {
233
        $originalArgs = \func_get_args();
234
 
235
        $date = $this;
236
 
237
        if (!is_numeric($value) || !(float) $value) {
238
            return $date->isMutable() ? $date : $date->avoidMutation();
239
        }
240
 
241
        $unit = self::singularUnit($unit);
242
        $metaUnits = [
243
            'millennium' => [static::YEARS_PER_MILLENNIUM, 'year'],
244
            'century' => [static::YEARS_PER_CENTURY, 'year'],
245
            'decade' => [static::YEARS_PER_DECADE, 'year'],
246
            'quarter' => [static::MONTHS_PER_QUARTER, 'month'],
247
        ];
248
 
249
        if (isset($metaUnits[$unit])) {
250
            [$factor, $unit] = $metaUnits[$unit];
251
            $value *= $factor;
252
        }
253
 
254
        if ($unit === 'weekday') {
255
            $weekendDays = static::getWeekendDays();
256
 
257
            if ($weekendDays !== [static::SATURDAY, static::SUNDAY]) {
258
                $absoluteValue = abs($value);
259
                $sign = $value / max(1, $absoluteValue);
260
                $weekDaysCount = 7 - min(6, \count(array_unique($weekendDays)));
261
                $weeks = floor($absoluteValue / $weekDaysCount);
262
 
263
                for ($diff = $absoluteValue % $weekDaysCount; $diff; $diff--) {
264
                    /** @var static $date */
265
                    $date = $date->addDays($sign);
266
 
267
                    while (\in_array($date->dayOfWeek, $weekendDays, true)) {
268
                        $date = $date->addDays($sign);
269
                    }
270
                }
271
 
272
                $value = $weeks * $sign;
273
                $unit = 'week';
274
            }
275
 
276
            $timeString = $date->toTimeString();
277
        } elseif ($canOverflow = (\in_array($unit, [
278
                'month',
279
                'year',
280
            ]) && ($overflow === false || (
281
                $overflow === null &&
282
                ($ucUnit = ucfirst($unit).'s') &&
283
                !($this->{'local'.$ucUnit.'Overflow'} ?? static::{'shouldOverflow'.$ucUnit}())
284
            )))) {
285
            $day = $date->day;
286
        }
287
 
288
        $value = (int) $value;
289
 
290
        if ($unit === 'milli' || $unit === 'millisecond') {
291
            $unit = 'microsecond';
292
            $value *= static::MICROSECONDS_PER_MILLISECOND;
293
        }
294
 
295
        // Work-around for bug https://bugs.php.net/bug.php?id=75642
296
        if ($unit === 'micro' || $unit === 'microsecond') {
297
            $microseconds = $this->micro + $value;
298
            $second = (int) floor($microseconds / static::MICROSECONDS_PER_SECOND);
299
            $microseconds %= static::MICROSECONDS_PER_SECOND;
300
            if ($microseconds < 0) {
301
                $microseconds += static::MICROSECONDS_PER_SECOND;
302
            }
303
            $date = $date->microseconds($microseconds);
304
            $unit = 'second';
305
            $value = $second;
306
        }
307
        $date = $date->modify("$value $unit");
308
 
309
        if (isset($timeString)) {
310
            $date = $date->setTimeFromTimeString($timeString);
311
        } elseif (isset($canOverflow, $day) && $canOverflow && $day !== $date->day) {
312
            $date = $date->modify('last day of previous month');
313
        }
314
 
315
        if (!$date) {
316
            throw new UnitException('Unable to add unit '.var_export($originalArgs, true));
317
        }
318
 
319
        return $date;
320
    }
321
 
322
    /**
323
     * Subtract given units to the current instance.
324
     *
325
     * @param string    $unit
326
     * @param int       $value
327
     * @param bool|null $overflow
328
     *
329
     * @return static
330
     */
331
    public function subUnit($unit, $value = 1, $overflow = null)
332
    {
333
        return $this->addUnit($unit, -$value, $overflow);
334
    }
335
 
336
    /**
337
     * Call native PHP DateTime/DateTimeImmutable sub() method.
338
     *
339
     * @param DateInterval $interval
340
     *
341
     * @return static
342
     */
343
    public function rawSub(DateInterval $interval)
344
    {
345
        return parent::sub($interval);
346
    }
347
 
348
    /**
349
     * Subtract given units or interval to the current instance.
350
     *
351
     * @example $date->sub('hour', 3)
352
     * @example $date->sub(15, 'days')
353
     * @example $date->sub(CarbonInterval::days(4))
354
     *
355
     * @param string|DateInterval|Closure|CarbonConverterInterface $unit
356
     * @param int                                                  $value
357
     * @param bool|null                                            $overflow
358
     *
359
     * @return static
360
     */
361
    #[ReturnTypeWillChange]
362
    public function sub($unit, $value = 1, $overflow = null)
363
    {
364
        if (\is_string($unit) && \func_num_args() === 1) {
365
            $unit = CarbonInterval::make($unit);
366
        }
367
 
368
        if ($unit instanceof CarbonConverterInterface) {
369
            return $this->resolveCarbon($unit->convertDate($this, true));
370
        }
371
 
372
        if ($unit instanceof Closure) {
373
            return $this->resolveCarbon($unit($this, true));
374
        }
375
 
376
        if ($unit instanceof DateInterval) {
377
            return parent::sub($unit);
378
        }
379
 
380
        if (is_numeric($unit)) {
381
            [$value, $unit] = [$unit, $value];
382
        }
383
 
384
        return $this->addUnit($unit, -(float) $value, $overflow);
385
    }
386
 
387
    /**
388
     * Subtract given units or interval to the current instance.
389
     *
390
     * @see sub()
391
     *
392
     * @param string|DateInterval $unit
393
     * @param int                 $value
394
     * @param bool|null           $overflow
395
     *
396
     * @return static
397
     */
398
    public function subtract($unit, $value = 1, $overflow = null)
399
    {
400
        if (\is_string($unit) && \func_num_args() === 1) {
401
            $unit = CarbonInterval::make($unit);
402
        }
403
 
404
        return $this->sub($unit, $value, $overflow);
405
    }
406
}