blob: 8fe008a5c27628d0c01b3d9d8377953036bd9a22 [file] [log] [blame]
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +02001<?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 */
Matthias Andreas Benkard1ba53812022-12-27 17:32:58 +010011
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +020012namespace Carbon\Traits;
13
14use Carbon\Carbon;
15use Carbon\CarbonImmutable;
16use Carbon\CarbonInterface;
17use Carbon\CarbonInterval;
18use Carbon\CarbonPeriod;
19use Carbon\Exceptions\UnitException;
20use Closure;
21use DateTime;
22use DateTimeImmutable;
23use ReturnTypeWillChange;
24
25/**
26 * Trait Converter.
27 *
28 * Change date into different string formats and types and
29 * handle the string cast.
30 *
31 * Depends on the following methods:
32 *
33 * @method static copy()
34 */
35trait Converter
36{
37 /**
38 * Format to use for __toString method when type juggling occurs.
39 *
40 * @var string|Closure|null
41 */
42 protected static $toStringFormat;
43
44 /**
45 * Reset the format used to the default when type juggling a Carbon instance to a string
46 *
47 * @return void
48 */
49 public static function resetToStringFormat()
50 {
51 static::setToStringFormat(null);
52 }
53
54 /**
55 * @deprecated To avoid conflict between different third-party libraries, static setters should not be used.
56 * You should rather let Carbon object being casted to string with DEFAULT_TO_STRING_FORMAT, and
57 * use other method or custom format passed to format() method if you need to dump an other string
58 * format.
59 *
60 * Set the default format used when type juggling a Carbon instance to a string
61 *
62 * @param string|Closure|null $format
63 *
64 * @return void
65 */
66 public static function setToStringFormat($format)
67 {
68 static::$toStringFormat = $format;
69 }
70
71 /**
72 * Returns the formatted date string on success or FALSE on failure.
73 *
74 * @see https://php.net/manual/en/datetime.format.php
75 *
76 * @param string $format
77 *
78 * @return string
79 */
80 #[ReturnTypeWillChange]
81 public function format($format)
82 {
83 $function = $this->localFormatFunction ?: static::$formatFunction;
84
85 if (!$function) {
86 return $this->rawFormat($format);
87 }
88
89 if (\is_string($function) && method_exists($this, $function)) {
90 $function = [$this, $function];
91 }
92
93 return $function(...\func_get_args());
94 }
95
96 /**
97 * @see https://php.net/manual/en/datetime.format.php
98 *
99 * @param string $format
100 *
101 * @return string
102 */
103 public function rawFormat($format)
104 {
105 return parent::format($format);
106 }
107
108 /**
109 * Format the instance as a string using the set format
110 *
111 * @example
112 * ```
113 * echo Carbon::now(); // Carbon instances can be casted to string
114 * ```
115 *
116 * @return string
117 */
118 public function __toString()
119 {
120 $format = $this->localToStringFormat ?? static::$toStringFormat;
121
122 return $format instanceof Closure
123 ? $format($this)
124 : $this->rawFormat($format ?: (
125 \defined('static::DEFAULT_TO_STRING_FORMAT')
126 ? static::DEFAULT_TO_STRING_FORMAT
127 : CarbonInterface::DEFAULT_TO_STRING_FORMAT
128 ));
129 }
130
131 /**
132 * Format the instance as date
133 *
134 * @example
135 * ```
136 * echo Carbon::now()->toDateString();
137 * ```
138 *
139 * @return string
140 */
141 public function toDateString()
142 {
143 return $this->rawFormat('Y-m-d');
144 }
145
146 /**
147 * Format the instance as a readable date
148 *
149 * @example
150 * ```
151 * echo Carbon::now()->toFormattedDateString();
152 * ```
153 *
154 * @return string
155 */
156 public function toFormattedDateString()
157 {
158 return $this->rawFormat('M j, Y');
159 }
160
161 /**
162 * Format the instance as time
163 *
164 * @example
165 * ```
166 * echo Carbon::now()->toTimeString();
167 * ```
168 *
169 * @param string $unitPrecision
170 *
171 * @return string
172 */
173 public function toTimeString($unitPrecision = 'second')
174 {
175 return $this->rawFormat(static::getTimeFormatByPrecision($unitPrecision));
176 }
177
178 /**
179 * Format the instance as date and time
180 *
181 * @example
182 * ```
183 * echo Carbon::now()->toDateTimeString();
184 * ```
185 *
186 * @param string $unitPrecision
187 *
188 * @return string
189 */
190 public function toDateTimeString($unitPrecision = 'second')
191 {
192 return $this->rawFormat('Y-m-d '.static::getTimeFormatByPrecision($unitPrecision));
193 }
194
195 /**
196 * Return a format from H:i to H:i:s.u according to given unit precision.
197 *
198 * @param string $unitPrecision "minute", "second", "millisecond" or "microsecond"
199 *
200 * @return string
201 */
202 public static function getTimeFormatByPrecision($unitPrecision)
203 {
204 switch (static::singularUnit($unitPrecision)) {
205 case 'minute':
206 return 'H:i';
207 case 'second':
208 return 'H:i:s';
209 case 'm':
210 case 'millisecond':
211 return 'H:i:s.v';
212 case 'µ':
213 case 'microsecond':
214 return 'H:i:s.u';
215 }
216
217 throw new UnitException('Precision unit expected among: minute, second, millisecond and microsecond.');
218 }
219
220 /**
221 * Format the instance as date and time T-separated with no timezone
222 *
223 * @example
224 * ```
225 * echo Carbon::now()->toDateTimeLocalString();
226 * echo "\n";
227 * echo Carbon::now()->toDateTimeLocalString('minute'); // You can specify precision among: minute, second, millisecond and microsecond
228 * ```
229 *
230 * @param string $unitPrecision
231 *
232 * @return string
233 */
234 public function toDateTimeLocalString($unitPrecision = 'second')
235 {
236 return $this->rawFormat('Y-m-d\T'.static::getTimeFormatByPrecision($unitPrecision));
237 }
238
239 /**
240 * Format the instance with day, date and time
241 *
242 * @example
243 * ```
244 * echo Carbon::now()->toDayDateTimeString();
245 * ```
246 *
247 * @return string
248 */
249 public function toDayDateTimeString()
250 {
251 return $this->rawFormat('D, M j, Y g:i A');
252 }
253
254 /**
255 * Format the instance as ATOM
256 *
257 * @example
258 * ```
259 * echo Carbon::now()->toAtomString();
260 * ```
261 *
262 * @return string
263 */
264 public function toAtomString()
265 {
266 return $this->rawFormat(DateTime::ATOM);
267 }
268
269 /**
270 * Format the instance as COOKIE
271 *
272 * @example
273 * ```
274 * echo Carbon::now()->toCookieString();
275 * ```
276 *
277 * @return string
278 */
279 public function toCookieString()
280 {
281 return $this->rawFormat(DateTime::COOKIE);
282 }
283
284 /**
285 * Format the instance as ISO8601
286 *
287 * @example
288 * ```
289 * echo Carbon::now()->toIso8601String();
290 * ```
291 *
292 * @return string
293 */
294 public function toIso8601String()
295 {
296 return $this->toAtomString();
297 }
298
299 /**
300 * Format the instance as RFC822
301 *
302 * @example
303 * ```
304 * echo Carbon::now()->toRfc822String();
305 * ```
306 *
307 * @return string
308 */
309 public function toRfc822String()
310 {
311 return $this->rawFormat(DateTime::RFC822);
312 }
313
314 /**
315 * Convert the instance to UTC and return as Zulu ISO8601
316 *
317 * @example
318 * ```
319 * echo Carbon::now()->toIso8601ZuluString();
320 * ```
321 *
322 * @param string $unitPrecision
323 *
324 * @return string
325 */
326 public function toIso8601ZuluString($unitPrecision = 'second')
327 {
328 return $this->avoidMutation()
329 ->utc()
330 ->rawFormat('Y-m-d\T'.static::getTimeFormatByPrecision($unitPrecision).'\Z');
331 }
332
333 /**
334 * Format the instance as RFC850
335 *
336 * @example
337 * ```
338 * echo Carbon::now()->toRfc850String();
339 * ```
340 *
341 * @return string
342 */
343 public function toRfc850String()
344 {
345 return $this->rawFormat(DateTime::RFC850);
346 }
347
348 /**
349 * Format the instance as RFC1036
350 *
351 * @example
352 * ```
353 * echo Carbon::now()->toRfc1036String();
354 * ```
355 *
356 * @return string
357 */
358 public function toRfc1036String()
359 {
360 return $this->rawFormat(DateTime::RFC1036);
361 }
362
363 /**
364 * Format the instance as RFC1123
365 *
366 * @example
367 * ```
368 * echo Carbon::now()->toRfc1123String();
369 * ```
370 *
371 * @return string
372 */
373 public function toRfc1123String()
374 {
375 return $this->rawFormat(DateTime::RFC1123);
376 }
377
378 /**
379 * Format the instance as RFC2822
380 *
381 * @example
382 * ```
383 * echo Carbon::now()->toRfc2822String();
384 * ```
385 *
386 * @return string
387 */
388 public function toRfc2822String()
389 {
390 return $this->rawFormat(DateTime::RFC2822);
391 }
392
393 /**
394 * Format the instance as RFC3339
395 *
396 * @param bool $extended
397 *
398 * @example
399 * ```
400 * echo Carbon::now()->toRfc3339String() . "\n";
401 * echo Carbon::now()->toRfc3339String(true) . "\n";
402 * ```
403 *
404 * @return string
405 */
406 public function toRfc3339String($extended = false)
407 {
408 $format = DateTime::RFC3339;
409 if ($extended) {
410 $format = DateTime::RFC3339_EXTENDED;
411 }
412
413 return $this->rawFormat($format);
414 }
415
416 /**
417 * Format the instance as RSS
418 *
419 * @example
420 * ```
421 * echo Carbon::now()->toRssString();
422 * ```
423 *
424 * @return string
425 */
426 public function toRssString()
427 {
428 return $this->rawFormat(DateTime::RSS);
429 }
430
431 /**
432 * Format the instance as W3C
433 *
434 * @example
435 * ```
436 * echo Carbon::now()->toW3cString();
437 * ```
438 *
439 * @return string
440 */
441 public function toW3cString()
442 {
443 return $this->rawFormat(DateTime::W3C);
444 }
445
446 /**
447 * Format the instance as RFC7231
448 *
449 * @example
450 * ```
451 * echo Carbon::now()->toRfc7231String();
452 * ```
453 *
454 * @return string
455 */
456 public function toRfc7231String()
457 {
458 return $this->avoidMutation()
459 ->setTimezone('GMT')
460 ->rawFormat(\defined('static::RFC7231_FORMAT') ? static::RFC7231_FORMAT : CarbonInterface::RFC7231_FORMAT);
461 }
462
463 /**
464 * Get default array representation.
465 *
466 * @example
467 * ```
468 * var_dump(Carbon::now()->toArray());
469 * ```
470 *
471 * @return array
472 */
473 public function toArray()
474 {
475 return [
476 'year' => $this->year,
477 'month' => $this->month,
478 'day' => $this->day,
479 'dayOfWeek' => $this->dayOfWeek,
480 'dayOfYear' => $this->dayOfYear,
481 'hour' => $this->hour,
482 'minute' => $this->minute,
483 'second' => $this->second,
484 'micro' => $this->micro,
485 'timestamp' => $this->timestamp,
486 'formatted' => $this->rawFormat(\defined('static::DEFAULT_TO_STRING_FORMAT') ? static::DEFAULT_TO_STRING_FORMAT : CarbonInterface::DEFAULT_TO_STRING_FORMAT),
487 'timezone' => $this->timezone,
488 ];
489 }
490
491 /**
492 * Get default object representation.
493 *
494 * @example
495 * ```
496 * var_dump(Carbon::now()->toObject());
497 * ```
498 *
499 * @return object
500 */
501 public function toObject()
502 {
503 return (object) $this->toArray();
504 }
505
506 /**
507 * Returns english human readable complete date string.
508 *
509 * @example
510 * ```
511 * echo Carbon::now()->toString();
512 * ```
513 *
514 * @return string
515 */
516 public function toString()
517 {
518 return $this->avoidMutation()->locale('en')->isoFormat('ddd MMM DD YYYY HH:mm:ss [GMT]ZZ');
519 }
520
521 /**
522 * Return the ISO-8601 string (ex: 1977-04-22T06:00:00Z, if $keepOffset truthy, offset will be kept:
523 * 1977-04-22T01:00:00-05:00).
524 *
525 * @example
526 * ```
527 * echo Carbon::now('America/Toronto')->toISOString() . "\n";
528 * echo Carbon::now('America/Toronto')->toISOString(true) . "\n";
529 * ```
530 *
531 * @param bool $keepOffset Pass true to keep the date offset. Else forced to UTC.
532 *
533 * @return null|string
534 */
535 public function toISOString($keepOffset = false)
536 {
537 if (!$this->isValid()) {
538 return null;
539 }
540
541 $yearFormat = $this->year < 0 || $this->year > 9999 ? 'YYYYYY' : 'YYYY';
542 $tzFormat = $keepOffset ? 'Z' : '[Z]';
543 $date = $keepOffset ? $this : $this->avoidMutation()->utc();
544
545 return $date->isoFormat("$yearFormat-MM-DD[T]HH:mm:ss.SSSSSS$tzFormat");
546 }
547
548 /**
549 * Return the ISO-8601 string (ex: 1977-04-22T06:00:00Z) with UTC timezone.
550 *
551 * @example
552 * ```
553 * echo Carbon::now('America/Toronto')->toJSON();
554 * ```
555 *
556 * @return null|string
557 */
558 public function toJSON()
559 {
560 return $this->toISOString();
561 }
562
563 /**
564 * Return native DateTime PHP object matching the current instance.
565 *
566 * @example
567 * ```
568 * var_dump(Carbon::now()->toDateTime());
569 * ```
570 *
571 * @return DateTime
572 */
573 public function toDateTime()
574 {
575 return new DateTime($this->rawFormat('Y-m-d H:i:s.u'), $this->getTimezone());
576 }
577
578 /**
579 * Return native toDateTimeImmutable PHP object matching the current instance.
580 *
581 * @example
582 * ```
583 * var_dump(Carbon::now()->toDateTimeImmutable());
584 * ```
585 *
586 * @return DateTimeImmutable
587 */
588 public function toDateTimeImmutable()
589 {
590 return new DateTimeImmutable($this->rawFormat('Y-m-d H:i:s.u'), $this->getTimezone());
591 }
592
593 /**
594 * @alias toDateTime
595 *
596 * Return native DateTime PHP object matching the current instance.
597 *
598 * @example
599 * ```
600 * var_dump(Carbon::now()->toDate());
601 * ```
602 *
603 * @return DateTime
604 */
605 public function toDate()
606 {
607 return $this->toDateTime();
608 }
609
610 /**
611 * Create a iterable CarbonPeriod object from current date to a given end date (and optional interval).
612 *
613 * @param \DateTimeInterface|Carbon|CarbonImmutable|int|null $end period end date or recurrences count if int
614 * @param int|\DateInterval|string|null $interval period default interval or number of the given $unit
615 * @param string|null $unit if specified, $interval must be an integer
616 *
617 * @return CarbonPeriod
618 */
619 public function toPeriod($end = null, $interval = null, $unit = null)
620 {
621 if ($unit) {
622 $interval = CarbonInterval::make("$interval ".static::pluralUnit($unit));
623 }
624
625 $period = (new CarbonPeriod())->setDateClass(static::class)->setStartDate($this);
626
627 if ($interval) {
628 $period->setDateInterval($interval);
629 }
630
631 if (\is_int($end) || \is_string($end) && ctype_digit($end)) {
632 $period->setRecurrences($end);
633 } elseif ($end) {
634 $period->setEndDate($end);
635 }
636
637 return $period;
638 }
639
640 /**
641 * Create a iterable CarbonPeriod object from current date to a given end date (and optional interval).
642 *
643 * @param \DateTimeInterface|Carbon|CarbonImmutable|null $end period end date
644 * @param int|\DateInterval|string|null $interval period default interval or number of the given $unit
645 * @param string|null $unit if specified, $interval must be an integer
646 *
647 * @return CarbonPeriod
648 */
649 public function range($end = null, $interval = null, $unit = null)
650 {
651 return $this->toPeriod($end, $interval, $unit);
652 }
653}