vendor/nesbot/carbon/src/Carbon/Traits/Creator.php line 187

Open in your IDE?
  1. <?php
  2. /**
  3.  * This file is part of the Carbon package.
  4.  *
  5.  * (c) Brian Nesbitt <brian@nesbot.com>
  6.  *
  7.  * For the full copyright and license information, please view the LICENSE
  8.  * file that was distributed with this source code.
  9.  */
  10. namespace Carbon\Traits;
  11. use Carbon\Carbon;
  12. use Carbon\CarbonImmutable;
  13. use Carbon\CarbonInterface;
  14. use Carbon\Exceptions\InvalidDateException;
  15. use Carbon\Exceptions\InvalidFormatException;
  16. use Carbon\Exceptions\OutOfRangeException;
  17. use Carbon\Translator;
  18. use Closure;
  19. use DateMalformedStringException;
  20. use DateTimeImmutable;
  21. use DateTimeInterface;
  22. use DateTimeZone;
  23. use Exception;
  24. use ReturnTypeWillChange;
  25. /**
  26.  * Trait Creator.
  27.  *
  28.  * Static creators.
  29.  *
  30.  * Depends on the following methods:
  31.  *
  32.  * @method static Carbon|CarbonImmutable getTestNow()
  33.  */
  34. trait Creator
  35. {
  36.     use ObjectInitialisation;
  37.     /**
  38.      * The errors that can occur.
  39.      *
  40.      * @var array
  41.      */
  42.     protected static $lastErrors;
  43.     /**
  44.      * Create a new Carbon instance.
  45.      *
  46.      * Please see the testing aids section (specifically static::setTestNow())
  47.      * for more on the possibility of this constructor returning a test instance.
  48.      *
  49.      * @param DateTimeInterface|string|null $time
  50.      * @param DateTimeZone|string|null      $tz
  51.      *
  52.      * @throws InvalidFormatException
  53.      */
  54.     public function __construct($time null$tz null)
  55.     {
  56.         if ($time instanceof DateTimeInterface) {
  57.             $time $this->constructTimezoneFromDateTime($time$tz)->format('Y-m-d H:i:s.u');
  58.         }
  59.         if (is_numeric($time) && (!\is_string($time) || !preg_match('/^\d{1,14}$/'$time))) {
  60.             $time = static::createFromTimestampUTC($time)->format('Y-m-d\TH:i:s.uP');
  61.         }
  62.         // If the class has a test now set and we are trying to create a now()
  63.         // instance then override as required
  64.         $isNow = empty($time) || $time === 'now';
  65.         if (method_exists(static::class, 'hasTestNow') &&
  66.             method_exists(static::class, 'getTestNow') &&
  67.             static::hasTestNow() &&
  68.             ($isNow || static::hasRelativeKeywords($time))
  69.         ) {
  70.             static::mockConstructorParameters($time$tz);
  71.         }
  72.         // Work-around for PHP bug https://bugs.php.net/bug.php?id=67127
  73.         if (!str_contains((string) .1'.')) {
  74.             $locale setlocale(LC_NUMERIC'0'); // @codeCoverageIgnore
  75.             setlocale(LC_NUMERIC'C'); // @codeCoverageIgnore
  76.         }
  77.         try {
  78.             parent::__construct($time ?: 'now', static::safeCreateDateTimeZone($tz) ?: null);
  79.         } catch (Exception $exception) {
  80.             throw new InvalidFormatException($exception->getMessage(), 0$exception);
  81.         }
  82.         $this->constructedObjectId spl_object_hash($this);
  83.         if (isset($locale)) {
  84.             setlocale(LC_NUMERIC$locale); // @codeCoverageIgnore
  85.         }
  86.         self::setLastErrors(parent::getLastErrors());
  87.     }
  88.     /**
  89.      * Get timezone from a datetime instance.
  90.      *
  91.      * @param DateTimeInterface        $date
  92.      * @param DateTimeZone|string|null $tz
  93.      *
  94.      * @return DateTimeInterface
  95.      */
  96.     private function constructTimezoneFromDateTime(DateTimeInterface $date, &$tz)
  97.     {
  98.         if ($tz !== null) {
  99.             $safeTz = static::safeCreateDateTimeZone($tz);
  100.             if ($safeTz) {
  101.                 return ($date instanceof DateTimeImmutable $date : clone $date)->setTimezone($safeTz);
  102.             }
  103.             return $date;
  104.         }
  105.         $tz $date->getTimezone();
  106.         return $date;
  107.     }
  108.     /**
  109.      * Update constructedObjectId on cloned.
  110.      */
  111.     public function __clone()
  112.     {
  113.         $this->constructedObjectId spl_object_hash($this);
  114.     }
  115.     /**
  116.      * Create a Carbon instance from a DateTime one.
  117.      *
  118.      * @param DateTimeInterface $date
  119.      *
  120.      * @return static
  121.      */
  122.     public static function instance($date)
  123.     {
  124.         if ($date instanceof static) {
  125.             return clone $date;
  126.         }
  127.         static::expectDateTime($date);
  128.         $instance = new static($date->format('Y-m-d H:i:s.u'), $date->getTimezone());
  129.         if ($date instanceof CarbonInterface) {
  130.             $settings $date->getSettings();
  131.             if (!$date->hasLocalTranslator()) {
  132.                 unset($settings['locale']);
  133.             }
  134.             $instance->settings($settings);
  135.         }
  136.         return $instance;
  137.     }
  138.     /**
  139.      * Create a carbon instance from a string.
  140.      *
  141.      * This is an alias for the constructor that allows better fluent syntax
  142.      * as it allows you to do Carbon::parse('Monday next week')->fn() rather
  143.      * than (new Carbon('Monday next week'))->fn().
  144.      *
  145.      * @param string|DateTimeInterface|null $time
  146.      * @param DateTimeZone|string|null      $tz
  147.      *
  148.      * @throws InvalidFormatException
  149.      *
  150.      * @return static
  151.      */
  152.     public static function rawParse($time null$tz null)
  153.     {
  154.         if ($time instanceof DateTimeInterface) {
  155.             return static::instance($time);
  156.         }
  157.         try {
  158.             return new static($time$tz);
  159.         } catch (Exception $exception) {
  160.             // @codeCoverageIgnoreStart
  161.             try {
  162.                 $date = @static::now($tz)->change($time);
  163.             } catch (DateMalformedStringException $ignoredException) {
  164.                 $date null;
  165.             }
  166.             // @codeCoverageIgnoreEnd
  167.             if (!$date) {
  168.                 throw new InvalidFormatException("Could not parse '$time': ".$exception->getMessage(), 0$exception);
  169.             }
  170.             return $date;
  171.         }
  172.     }
  173.     /**
  174.      * Create a carbon instance from a string.
  175.      *
  176.      * This is an alias for the constructor that allows better fluent syntax
  177.      * as it allows you to do Carbon::parse('Monday next week')->fn() rather
  178.      * than (new Carbon('Monday next week'))->fn().
  179.      *
  180.      * @param string|DateTimeInterface|null $time
  181.      * @param DateTimeZone|string|null      $tz
  182.      *
  183.      * @throws InvalidFormatException
  184.      *
  185.      * @return static
  186.      */
  187.     public static function parse($time null$tz null)
  188.     {
  189.         $function = static::$parseFunction;
  190.         if (!$function) {
  191.             return static::rawParse($time$tz);
  192.         }
  193.         if (\is_string($function) && method_exists(static::class, $function)) {
  194.             $function = [static::class, $function];
  195.         }
  196.         return $function(...\func_get_args());
  197.     }
  198.     /**
  199.      * Create a carbon instance from a localized string (in French, Japanese, Arabic, etc.).
  200.      *
  201.      * @param string                   $time   date/time string in the given language (may also contain English).
  202.      * @param string|null              $locale if locale is null or not specified, current global locale will be
  203.      *                                         used instead.
  204.      * @param DateTimeZone|string|null $tz     optional timezone for the new instance.
  205.      *
  206.      * @throws InvalidFormatException
  207.      *
  208.      * @return static
  209.      */
  210.     public static function parseFromLocale($time$locale null$tz null)
  211.     {
  212.         return static::rawParse(static::translateTimeString($time$locale'en'), $tz);
  213.     }
  214.     /**
  215.      * Get a Carbon instance for the current date and time.
  216.      *
  217.      * @param DateTimeZone|string|null $tz
  218.      *
  219.      * @return static
  220.      */
  221.     public static function now($tz null)
  222.     {
  223.         return new static(null$tz);
  224.     }
  225.     /**
  226.      * Create a Carbon instance for today.
  227.      *
  228.      * @param DateTimeZone|string|null $tz
  229.      *
  230.      * @return static
  231.      */
  232.     public static function today($tz null)
  233.     {
  234.         return static::rawParse('today'$tz);
  235.     }
  236.     /**
  237.      * Create a Carbon instance for tomorrow.
  238.      *
  239.      * @param DateTimeZone|string|null $tz
  240.      *
  241.      * @return static
  242.      */
  243.     public static function tomorrow($tz null)
  244.     {
  245.         return static::rawParse('tomorrow'$tz);
  246.     }
  247.     /**
  248.      * Create a Carbon instance for yesterday.
  249.      *
  250.      * @param DateTimeZone|string|null $tz
  251.      *
  252.      * @return static
  253.      */
  254.     public static function yesterday($tz null)
  255.     {
  256.         return static::rawParse('yesterday'$tz);
  257.     }
  258.     /**
  259.      * Create a Carbon instance for the greatest supported date.
  260.      *
  261.      * @return static
  262.      */
  263.     public static function maxValue()
  264.     {
  265.         if (self::$PHPIntSize === 4) {
  266.             // 32 bit
  267.             return static::createFromTimestamp(PHP_INT_MAX); // @codeCoverageIgnore
  268.         }
  269.         // 64 bit
  270.         return static::create(99991231235959);
  271.     }
  272.     /**
  273.      * Create a Carbon instance for the lowest supported date.
  274.      *
  275.      * @return static
  276.      */
  277.     public static function minValue()
  278.     {
  279.         if (self::$PHPIntSize === 4) {
  280.             // 32 bit
  281.             return static::createFromTimestamp(~PHP_INT_MAX); // @codeCoverageIgnore
  282.         }
  283.         // 64 bit
  284.         return static::create(111000);
  285.     }
  286.     private static function assertBetween($unit$value$min$max)
  287.     {
  288.         if (static::isStrictModeEnabled() && ($value $min || $value $max)) {
  289.             throw new OutOfRangeException($unit$min$max$value);
  290.         }
  291.     }
  292.     private static function createNowInstance($tz)
  293.     {
  294.         if (!static::hasTestNow()) {
  295.             return static::now($tz);
  296.         }
  297.         $now = static::getTestNow();
  298.         if ($now instanceof Closure) {
  299.             return $now(static::now($tz));
  300.         }
  301.         return $now->avoidMutation()->tz($tz);
  302.     }
  303.     /**
  304.      * Create a new Carbon instance from a specific date and time.
  305.      *
  306.      * If any of $year, $month or $day are set to null their now() values will
  307.      * be used.
  308.      *
  309.      * If $hour is null it will be set to its now() value and the default
  310.      * values for $minute and $second will be their now() values.
  311.      *
  312.      * If $hour is not null then the default values for $minute and $second
  313.      * will be 0.
  314.      *
  315.      * @param DateTimeInterface|int|null $year
  316.      * @param int|null                   $month
  317.      * @param int|null                   $day
  318.      * @param int|null                   $hour
  319.      * @param int|null                   $minute
  320.      * @param int|null                   $second
  321.      * @param DateTimeZone|string|null   $tz
  322.      *
  323.      * @throws InvalidFormatException
  324.      *
  325.      * @return static|false
  326.      */
  327.     public static function create($year 0$month 1$day 1$hour 0$minute 0$second 0$tz null)
  328.     {
  329.         if ((\is_string($year) && !is_numeric($year)) || $year instanceof DateTimeInterface) {
  330.             return static::parse($year$tz ?: (\is_string($month) || $month instanceof DateTimeZone $month null));
  331.         }
  332.         $defaults null;
  333.         $getDefault = function ($unit) use ($tz, &$defaults) {
  334.             if ($defaults === null) {
  335.                 $now self::createNowInstance($tz);
  336.                 $defaults array_combine([
  337.                     'year',
  338.                     'month',
  339.                     'day',
  340.                     'hour',
  341.                     'minute',
  342.                     'second',
  343.                 ], explode('-'$now->rawFormat('Y-n-j-G-i-s.u')));
  344.             }
  345.             return $defaults[$unit];
  346.         };
  347.         $year $year ?? $getDefault('year');
  348.         $month $month ?? $getDefault('month');
  349.         $day $day ?? $getDefault('day');
  350.         $hour $hour ?? $getDefault('hour');
  351.         $minute $minute ?? $getDefault('minute');
  352.         $second = (float) ($second ?? $getDefault('second'));
  353.         self::assertBetween('month'$month099);
  354.         self::assertBetween('day'$day099);
  355.         self::assertBetween('hour'$hour099);
  356.         self::assertBetween('minute'$minute099);
  357.         self::assertBetween('second'$second099);
  358.         $fixYear null;
  359.         if ($year 0) {
  360.             $fixYear $year;
  361.             $year 0;
  362.         } elseif ($year 9999) {
  363.             $fixYear $year 9999;
  364.             $year 9999;
  365.         }
  366.         $second = ($second 10 '0' '').number_format($second6);
  367.         $instance = static::rawCreateFromFormat('!Y-n-j G:i:s.u'sprintf('%s-%s-%s %s:%02s:%02s'$year$month$day$hour$minute$second), $tz);
  368.         if ($fixYear !== null) {
  369.             $instance $instance->addYears($fixYear);
  370.         }
  371.         return $instance;
  372.     }
  373.     /**
  374.      * Create a new safe Carbon instance from a specific date and time.
  375.      *
  376.      * If any of $year, $month or $day are set to null their now() values will
  377.      * be used.
  378.      *
  379.      * If $hour is null it will be set to its now() value and the default
  380.      * values for $minute and $second will be their now() values.
  381.      *
  382.      * If $hour is not null then the default values for $minute and $second
  383.      * will be 0.
  384.      *
  385.      * If one of the set values is not valid, an InvalidDateException
  386.      * will be thrown.
  387.      *
  388.      * @param int|null                 $year
  389.      * @param int|null                 $month
  390.      * @param int|null                 $day
  391.      * @param int|null                 $hour
  392.      * @param int|null                 $minute
  393.      * @param int|null                 $second
  394.      * @param DateTimeZone|string|null $tz
  395.      *
  396.      * @throws InvalidDateException
  397.      *
  398.      * @return static|false
  399.      */
  400.     public static function createSafe($year null$month null$day null$hour null$minute null$second null$tz null)
  401.     {
  402.         $fields = static::getRangesByUnit();
  403.         foreach ($fields as $field => $range) {
  404.             if ($$field !== null && (!\is_int($$field) || $$field $range[0] || $$field $range[1])) {
  405.                 if (static::isStrictModeEnabled()) {
  406.                     throw new InvalidDateException($field, $$field);
  407.                 }
  408.                 return false;
  409.             }
  410.         }
  411.         $instance = static::create($year$month$day$hour$minute$second$tz);
  412.         foreach (array_reverse($fields) as $field => $range) {
  413.             if ($$field !== null && (!\is_int($$field) || $$field !== $instance->$field)) {
  414.                 if (static::isStrictModeEnabled()) {
  415.                     throw new InvalidDateException($field, $$field);
  416.                 }
  417.                 return false;
  418.             }
  419.         }
  420.         return $instance;
  421.     }
  422.     /**
  423.      * Create a new Carbon instance from a specific date and time using strict validation.
  424.      *
  425.      * @see create()
  426.      *
  427.      * @param int|null                 $year
  428.      * @param int|null                 $month
  429.      * @param int|null                 $day
  430.      * @param int|null                 $hour
  431.      * @param int|null                 $minute
  432.      * @param int|null                 $second
  433.      * @param DateTimeZone|string|null $tz
  434.      *
  435.      * @throws InvalidFormatException
  436.      *
  437.      * @return static
  438.      */
  439.     public static function createStrict(?int $year 0, ?int $month 1, ?int $day 1, ?int $hour 0, ?int $minute 0, ?int $second 0$tz null): self
  440.     {
  441.         $initialStrictMode = static::isStrictModeEnabled();
  442.         static::useStrictMode(true);
  443.         try {
  444.             $date = static::create($year$month$day$hour$minute$second$tz);
  445.         } finally {
  446.             static::useStrictMode($initialStrictMode);
  447.         }
  448.         return $date;
  449.     }
  450.     /**
  451.      * Create a Carbon instance from just a date. The time portion is set to now.
  452.      *
  453.      * @param int|null                 $year
  454.      * @param int|null                 $month
  455.      * @param int|null                 $day
  456.      * @param DateTimeZone|string|null $tz
  457.      *
  458.      * @throws InvalidFormatException
  459.      *
  460.      * @return static
  461.      */
  462.     public static function createFromDate($year null$month null$day null$tz null)
  463.     {
  464.         return static::create($year$month$daynullnullnull$tz);
  465.     }
  466.     /**
  467.      * Create a Carbon instance from just a date. The time portion is set to midnight.
  468.      *
  469.      * @param int|null                 $year
  470.      * @param int|null                 $month
  471.      * @param int|null                 $day
  472.      * @param DateTimeZone|string|null $tz
  473.      *
  474.      * @throws InvalidFormatException
  475.      *
  476.      * @return static
  477.      */
  478.     public static function createMidnightDate($year null$month null$day null$tz null)
  479.     {
  480.         return static::create($year$month$day000$tz);
  481.     }
  482.     /**
  483.      * Create a Carbon instance from just a time. The date portion is set to today.
  484.      *
  485.      * @param int|null                 $hour
  486.      * @param int|null                 $minute
  487.      * @param int|null                 $second
  488.      * @param DateTimeZone|string|null $tz
  489.      *
  490.      * @throws InvalidFormatException
  491.      *
  492.      * @return static
  493.      */
  494.     public static function createFromTime($hour 0$minute 0$second 0$tz null)
  495.     {
  496.         return static::create(nullnullnull$hour$minute$second$tz);
  497.     }
  498.     /**
  499.      * Create a Carbon instance from a time string. The date portion is set to today.
  500.      *
  501.      * @param string                   $time
  502.      * @param DateTimeZone|string|null $tz
  503.      *
  504.      * @throws InvalidFormatException
  505.      *
  506.      * @return static
  507.      */
  508.     public static function createFromTimeString($time$tz null)
  509.     {
  510.         return static::today($tz)->setTimeFromTimeString($time);
  511.     }
  512.     /**
  513.      * @param string                         $format     Datetime format
  514.      * @param string                         $time
  515.      * @param DateTimeZone|string|false|null $originalTz
  516.      *
  517.      * @return DateTimeInterface|false
  518.      */
  519.     private static function createFromFormatAndTimezone($format$time$originalTz)
  520.     {
  521.         // Work-around for https://bugs.php.net/bug.php?id=75577
  522.         // @codeCoverageIgnoreStart
  523.         if (version_compare(PHP_VERSION'7.3.0-dev''<')) {
  524.             $format str_replace('.v''.u'$format);
  525.         }
  526.         // @codeCoverageIgnoreEnd
  527.         if ($originalTz === null) {
  528.             return parent::createFromFormat($format, (string) $time);
  529.         }
  530.         $tz \is_int($originalTz)
  531.             ? @timezone_name_from_abbr('', (int) ($originalTz * static::MINUTES_PER_HOUR * static::SECONDS_PER_MINUTE), 1)
  532.             : $originalTz;
  533.         $tz = static::safeCreateDateTimeZone($tz$originalTz);
  534.         if ($tz === false) {
  535.             return false;
  536.         }
  537.         return parent::createFromFormat($format, (string) $time$tz);
  538.     }
  539.     /**
  540.      * Create a Carbon instance from a specific format.
  541.      *
  542.      * @param string                         $format Datetime format
  543.      * @param string                         $time
  544.      * @param DateTimeZone|string|false|null $tz
  545.      *
  546.      * @throws InvalidFormatException
  547.      *
  548.      * @return static|false
  549.      */
  550.     public static function rawCreateFromFormat($format$time$tz null)
  551.     {
  552.         // Work-around for https://bugs.php.net/bug.php?id=80141
  553.         $format preg_replace('/(?<!\\\\)((?:\\\\{2})*)c/''$1Y-m-d\TH:i:sP'$format);
  554.         if (preg_match('/(?<!\\\\)(?:\\\\{2})*(a|A)/'$format$aMatchesPREG_OFFSET_CAPTURE) &&
  555.             preg_match('/(?<!\\\\)(?:\\\\{2})*(h|g|H|G)/'$format$hMatchesPREG_OFFSET_CAPTURE) &&
  556.             $aMatches[1][1] < $hMatches[1][1] &&
  557.             preg_match('/(am|pm|AM|PM)/'$time)
  558.         ) {
  559.             $format preg_replace('/^(.*)(?<!\\\\)((?:\\\\{2})*)(a|A)(.*)$/U''$1$2$4 $3'$format);
  560.             $time preg_replace('/^(.*)(am|pm|AM|PM)(.*)$/U''$1$3 $2'$time);
  561.         }
  562.         if ($tz === false) {
  563.             $tz null;
  564.         }
  565.         // First attempt to create an instance, so that error messages are based on the unmodified format.
  566.         $date self::createFromFormatAndTimezone($format$time$tz);
  567.         $lastErrors parent::getLastErrors();
  568.         /** @var \Carbon\CarbonImmutable|\Carbon\Carbon|null $mock */
  569.         $mock = static::getMockedTestNow($tz);
  570.         if ($mock && $date instanceof DateTimeInterface) {
  571.             // Set timezone from mock if custom timezone was neither given directly nor as a part of format.
  572.             // First let's skip the part that will be ignored by the parser.
  573.             $nonEscaped '(?<!\\\\)(\\\\{2})*';
  574.             $nonIgnored preg_replace("/^.*{$nonEscaped}!/s"''$format);
  575.             if ($tz === null && !preg_match("/{$nonEscaped}[eOPT]/"$nonIgnored)) {
  576.                 $tz = clone $mock->getTimezone();
  577.             }
  578.             $mock $mock->copy();
  579.             // Prepend mock datetime only if the format does not contain non escaped unix epoch reset flag.
  580.             if (!preg_match("/{$nonEscaped}[!|]/"$format)) {
  581.                 if (preg_match('/[HhGgisvuB]/'$format)) {
  582.                     $mock $mock->setTime(00);
  583.                 }
  584.                 $format = static::MOCK_DATETIME_FORMAT.' '.$format;
  585.                 $time = ($mock instanceof self $mock->rawFormat(static::MOCK_DATETIME_FORMAT) : $mock->format(static::MOCK_DATETIME_FORMAT)).' '.$time;
  586.             }
  587.             // Regenerate date from the modified format to base result on the mocked instance instead of now.
  588.             $date self::createFromFormatAndTimezone($format$time$tz);
  589.         }
  590.         if ($date instanceof DateTimeInterface) {
  591.             $instance = static::instance($date);
  592.             $instance::setLastErrors($lastErrors);
  593.             return $instance;
  594.         }
  595.         if (static::isStrictModeEnabled()) {
  596.             throw new InvalidFormatException(implode(PHP_EOL$lastErrors['errors']));
  597.         }
  598.         return false;
  599.     }
  600.     /**
  601.      * Create a Carbon instance from a specific format.
  602.      *
  603.      * @param string                         $format Datetime format
  604.      * @param string                         $time
  605.      * @param DateTimeZone|string|false|null $tz
  606.      *
  607.      * @throws InvalidFormatException
  608.      *
  609.      * @return static|false
  610.      */
  611.     #[ReturnTypeWillChange]
  612.     public static function createFromFormat($format$time$tz null)
  613.     {
  614.         $function = static::$createFromFormatFunction;
  615.         if (!$function) {
  616.             return static::rawCreateFromFormat($format$time$tz);
  617.         }
  618.         if (\is_string($function) && method_exists(static::class, $function)) {
  619.             $function = [static::class, $function];
  620.         }
  621.         return $function(...\func_get_args());
  622.     }
  623.     /**
  624.      * Create a Carbon instance from a specific ISO format (same replacements as ->isoFormat()).
  625.      *
  626.      * @param string                                             $format     Datetime format
  627.      * @param string                                             $time
  628.      * @param DateTimeZone|string|false|null                     $tz         optional timezone
  629.      * @param string|null                                        $locale     locale to be used for LTS, LT, LL, LLL, etc. macro-formats (en by fault, unneeded if no such macro-format in use)
  630.      * @param \Symfony\Component\Translation\TranslatorInterface $translator optional custom translator to use for macro-formats
  631.      *
  632.      * @throws InvalidFormatException
  633.      *
  634.      * @return static|false
  635.      */
  636.     public static function createFromIsoFormat($format$time$tz null$locale 'en'$translator null)
  637.     {
  638.         $format preg_replace_callback('/(?<!\\\\)(\\\\{2})*(LTS|LT|[Ll]{1,4})/', function ($match) use ($locale$translator) {
  639.             [$code] = $match;
  640.             static $formats null;
  641.             if ($formats === null) {
  642.                 $translator $translator ?: Translator::get($locale);
  643.                 $formats = [
  644.                     'LT' => static::getTranslationMessageWith($translator'formats.LT'$locale'h:mm A'),
  645.                     'LTS' => static::getTranslationMessageWith($translator'formats.LTS'$locale'h:mm:ss A'),
  646.                     'L' => static::getTranslationMessageWith($translator'formats.L'$locale'MM/DD/YYYY'),
  647.                     'LL' => static::getTranslationMessageWith($translator'formats.LL'$locale'MMMM D, YYYY'),
  648.                     'LLL' => static::getTranslationMessageWith($translator'formats.LLL'$locale'MMMM D, YYYY h:mm A'),
  649.                     'LLLL' => static::getTranslationMessageWith($translator'formats.LLLL'$locale'dddd, MMMM D, YYYY h:mm A'),
  650.                 ];
  651.             }
  652.             return $formats[$code] ?? preg_replace_callback(
  653.                 '/MMMM|MM|DD|dddd/',
  654.                 function ($code) {
  655.                     return mb_substr($code[0], 1);
  656.                 },
  657.                 $formats[strtoupper($code)] ?? ''
  658.             );
  659.         }, $format);
  660.         $format preg_replace_callback('/(?<!\\\\)(\\\\{2})*('.CarbonInterface::ISO_FORMAT_REGEXP.'|[A-Za-z])/', function ($match) {
  661.             [$code] = $match;
  662.             static $replacements null;
  663.             if ($replacements === null) {
  664.                 $replacements = [
  665.                     'OD' => 'd',
  666.                     'OM' => 'M',
  667.                     'OY' => 'Y',
  668.                     'OH' => 'G',
  669.                     'Oh' => 'g',
  670.                     'Om' => 'i',
  671.                     'Os' => 's',
  672.                     'D' => 'd',
  673.                     'DD' => 'd',
  674.                     'Do' => 'd',
  675.                     'd' => '!',
  676.                     'dd' => '!',
  677.                     'ddd' => 'D',
  678.                     'dddd' => 'D',
  679.                     'DDD' => 'z',
  680.                     'DDDD' => 'z',
  681.                     'DDDo' => 'z',
  682.                     'e' => '!',
  683.                     'E' => '!',
  684.                     'H' => 'G',
  685.                     'HH' => 'H',
  686.                     'h' => 'g',
  687.                     'hh' => 'h',
  688.                     'k' => 'G',
  689.                     'kk' => 'G',
  690.                     'hmm' => 'gi',
  691.                     'hmmss' => 'gis',
  692.                     'Hmm' => 'Gi',
  693.                     'Hmmss' => 'Gis',
  694.                     'm' => 'i',
  695.                     'mm' => 'i',
  696.                     'a' => 'a',
  697.                     'A' => 'a',
  698.                     's' => 's',
  699.                     'ss' => 's',
  700.                     'S' => '*',
  701.                     'SS' => '*',
  702.                     'SSS' => '*',
  703.                     'SSSS' => '*',
  704.                     'SSSSS' => '*',
  705.                     'SSSSSS' => 'u',
  706.                     'SSSSSSS' => 'u*',
  707.                     'SSSSSSSS' => 'u*',
  708.                     'SSSSSSSSS' => 'u*',
  709.                     'M' => 'm',
  710.                     'MM' => 'm',
  711.                     'MMM' => 'M',
  712.                     'MMMM' => 'M',
  713.                     'Mo' => 'm',
  714.                     'Q' => '!',
  715.                     'Qo' => '!',
  716.                     'G' => '!',
  717.                     'GG' => '!',
  718.                     'GGG' => '!',
  719.                     'GGGG' => '!',
  720.                     'GGGGG' => '!',
  721.                     'g' => '!',
  722.                     'gg' => '!',
  723.                     'ggg' => '!',
  724.                     'gggg' => '!',
  725.                     'ggggg' => '!',
  726.                     'W' => '!',
  727.                     'WW' => '!',
  728.                     'Wo' => '!',
  729.                     'w' => '!',
  730.                     'ww' => '!',
  731.                     'wo' => '!',
  732.                     'x' => 'U???',
  733.                     'X' => 'U',
  734.                     'Y' => 'Y',
  735.                     'YY' => 'y',
  736.                     'YYYY' => 'Y',
  737.                     'YYYYY' => 'Y',
  738.                     'YYYYYY' => 'Y',
  739.                     'z' => 'e',
  740.                     'zz' => 'e',
  741.                     'Z' => 'e',
  742.                     'ZZ' => 'e',
  743.                 ];
  744.             }
  745.             $format $replacements[$code] ?? '?';
  746.             if ($format === '!') {
  747.                 throw new InvalidFormatException("Format $code not supported for creation.");
  748.             }
  749.             return $format;
  750.         }, $format);
  751.         return static::rawCreateFromFormat($format$time$tz);
  752.     }
  753.     /**
  754.      * Create a Carbon instance from a specific format and a string in a given language.
  755.      *
  756.      * @param string                         $format Datetime format
  757.      * @param string                         $locale
  758.      * @param string                         $time
  759.      * @param DateTimeZone|string|false|null $tz
  760.      *
  761.      * @throws InvalidFormatException
  762.      *
  763.      * @return static|false
  764.      */
  765.     public static function createFromLocaleFormat($format$locale$time$tz null)
  766.     {
  767.         $format preg_replace_callback(
  768.             '/(?:\\\\[a-zA-Z]|[bfkqCEJKQRV]){2,}/',
  769.             static function (array $match) use ($locale): string {
  770.                 $word str_replace('\\'''$match[0]);
  771.                 $translatedWord = static::translateTimeString($word$locale'en');
  772.                 return $word === $translatedWord
  773.                     $match[0]
  774.                     : preg_replace('/[a-zA-Z]/''\\\\$0'$translatedWord);
  775.             },
  776.             $format
  777.         );
  778.         return static::rawCreateFromFormat($format, static::translateTimeString($time$locale'en'), $tz);
  779.     }
  780.     /**
  781.      * Create a Carbon instance from a specific ISO format and a string in a given language.
  782.      *
  783.      * @param string                         $format Datetime ISO format
  784.      * @param string                         $locale
  785.      * @param string                         $time
  786.      * @param DateTimeZone|string|false|null $tz
  787.      *
  788.      * @throws InvalidFormatException
  789.      *
  790.      * @return static|false
  791.      */
  792.     public static function createFromLocaleIsoFormat($format$locale$time$tz null)
  793.     {
  794.         $time = static::translateTimeString($time$locale'en'CarbonInterface::TRANSLATE_MONTHS CarbonInterface::TRANSLATE_DAYS CarbonInterface::TRANSLATE_MERIDIEM);
  795.         return static::createFromIsoFormat($format$time$tz$locale);
  796.     }
  797.     /**
  798.      * Make a Carbon instance from given variable if possible.
  799.      *
  800.      * Always return a new instance. Parse only strings and only these likely to be dates (skip intervals
  801.      * and recurrences). Throw an exception for invalid format, but otherwise return null.
  802.      *
  803.      * @param mixed $var
  804.      *
  805.      * @throws InvalidFormatException
  806.      *
  807.      * @return static|null
  808.      */
  809.     public static function make($var)
  810.     {
  811.         if ($var instanceof DateTimeInterface) {
  812.             return static::instance($var);
  813.         }
  814.         $date null;
  815.         if (\is_string($var)) {
  816.             $var trim($var);
  817.             if (!preg_match('/^P[\dT]/'$var) &&
  818.                 !preg_match('/^R\d/'$var) &&
  819.                 preg_match('/[a-z\d]/i'$var)
  820.             ) {
  821.                 $date = static::parse($var);
  822.             }
  823.         }
  824.         return $date;
  825.     }
  826.     /**
  827.      * Set last errors.
  828.      *
  829.      * @param array|bool $lastErrors
  830.      *
  831.      * @return void
  832.      */
  833.     private static function setLastErrors($lastErrors)
  834.     {
  835.         if (\is_array($lastErrors) || $lastErrors === false) {
  836.             static::$lastErrors \is_array($lastErrors) ? $lastErrors : [
  837.                 'warning_count' => 0,
  838.                 'warnings' => [],
  839.                 'error_count' => 0,
  840.                 'errors' => [],
  841.             ];
  842.         }
  843.     }
  844.     /**
  845.      * {@inheritdoc}
  846.      *
  847.      * @return array
  848.      */
  849.     #[ReturnTypeWillChange]
  850.     public static function getLastErrors()
  851.     {
  852.         return static::$lastErrors;
  853.     }
  854. }