<?php

/**
 * This file is part of the Carbon package.
 *
 * (c) Brian Nesbitt <brian@nesbot.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
namespace Carbon\Traits;

use BadMethodCallException;
use Carbon\CarbonInterface;
use Carbon\CarbonTimeZone;
use Closure;
use DateTime;
use DateTimeInterface;
use InvalidArgumentException;
use ReflectionException;

/**
 * A simple API extension for DateTime.
 *
 * <autodoc generated by `composer phpdoc`>
 *
 * @property      int            $year
 * @property      int            $yearIso
 * @property      int            $month
 * @property      int            $day
 * @property      int            $hour
 * @property      int            $minute
 * @property      int            $second
 * @property      int            $micro
 * @property      int            $microsecond
 * @property      int            $timestamp                                                                          seconds since the Unix Epoch
 * @property      string         $englishDayOfWeek                                                                   the day of week in English
 * @property      string         $shortEnglishDayOfWeek                                                              the abbreviated day of week in English
 * @property      string         $englishMonth                                                                       the day of week in English
 * @property      string         $shortEnglishMonth                                                                  the abbreviated day of week in English
 * @property      string         $localeDayOfWeek                                                                    the day of week in current locale LC_TIME
 * @property      string         $shortLocaleDayOfWeek                                                               the abbreviated day of week in current locale LC_TIME
 * @property      string         $localeMonth                                                                        the month in current locale LC_TIME
 * @property      string         $shortLocaleMonth                                                                   the abbreviated month in current locale LC_TIME
 * @property      int            $milliseconds
 * @property      int            $millisecond
 * @property      int            $milli
 * @property      int            $week                                                                               1 through 53
 * @property      int            $isoWeek                                                                            1 through 53
 * @property      int            $weekYear                                                                           year according to week format
 * @property      int            $isoWeekYear                                                                        year according to ISO week format
 * @property      int            $dayOfYear                                                                          1 through 366
 * @property      int            $age                                                                                does a diffInYears() with default parameters
 * @property      int            $offset                                                                             the timezone offset in seconds from UTC
 * @property      int            $offsetMinutes                                                                      the timezone offset in minutes from UTC
 * @property      int            $offsetHours                                                                        the timezone offset in hours from UTC
 * @property      CarbonTimeZone $timezone                                                                           the current timezone
 * @property      CarbonTimeZone $tz                                                                                 alias of $timezone
 * @property-read int            $dayOfWeek                                                                          0 (for Sunday) through 6 (for Saturday)
 * @property-read int            $dayOfWeekIso                                                                       1 (for Monday) through 7 (for Sunday)
 * @property-read int            $weekOfYear                                                                         ISO-8601 week number of year, weeks starting on Monday
 * @property-read int            $daysInMonth                                                                        number of days in the given month
 * @property-read string         $latinMeridiem                                                                      "am"/"pm" (Ante meridiem or Post meridiem latin lowercase mark)
 * @property-read string         $latinUpperMeridiem                                                                 "AM"/"PM" (Ante meridiem or Post meridiem latin uppercase mark)
 * @property-read string         $dayName                                                                            long name of weekday translated according to Carbon locale, in english if no translation available for current language
 * @property-read string         $shortDayName                                                                       short name of weekday translated according to Carbon locale, in english if no translation available for current language
 * @property-read string         $minDayName                                                                         very short name of weekday translated according to Carbon locale, in english if no translation available for current language
 * @property-read string         $monthName                                                                          long name of month translated according to Carbon locale, in english if no translation available for current language
 * @property-read string         $shortMonthName                                                                     short name of month translated according to Carbon locale, in english if no translation available for current language
 * @property-read string         $meridiem                                                                           lowercase meridiem mark translated according to Carbon locale, in latin if no translation available for current language
 * @property-read string         $upperMeridiem                                                                      uppercase meridiem mark translated according to Carbon locale, in latin if no translation available for current language
 * @property-read int            $noZeroHour                                                                         current hour from 1 to 24
 * @property-read int            $weeksInYear                                                                        51 through 53
 * @property-read int            $isoWeeksInYear                                                                     51 through 53
 * @property-read int            $weekOfMonth                                                                        1 through 5
 * @property-read int            $weekNumberInMonth                                                                  1 through 5
 * @property-read int            $firstWeekDay                                                                       0 through 6
 * @property-read int            $lastWeekDay                                                                        0 through 6
 * @property-read int            $daysInYear                                                                         365 or 366
 * @property-read int            $quarter                                                                            the quarter of this instance, 1 - 4
 * @property-read int            $decade                                                                             the decade of this instance
 * @property-read int            $century                                                                            the century of this instance
 * @property-read int            $millennium                                                                         the millennium of this instance
 * @property-read bool           $dst                                                                                daylight savings time indicator, true if DST, false otherwise
 * @property-read bool           $local                                                                              checks if the timezone is local, true if local, false otherwise
 * @property-read bool           $utc                                                                                checks if the timezone is UTC, true if UTC, false otherwise
 * @property-read string         $timezoneName                                                                       the current timezone name
 * @property-read string         $tzName                                                                             alias of $timezoneName
 * @property-read string         $timezoneAbbreviatedName                                                            the current timezone abbreviated name
 * @property-read string         $tzAbbrName                                                                         alias of $timezoneAbbreviatedName
 * @property-read string         $locale                                                                             locale of the current instance
 *
 * @method        bool           isUtc()                                                                             Check if the current instance has UTC timezone. (Both isUtc and isUTC cases are valid.)
 * @method        bool           isLocal()                                                                           Check if the current instance has non-UTC timezone.
 * @method        bool           isValid()                                                                           Check if the current instance is a valid date.
 * @method        bool           isDST()                                                                             Check if the current instance is in a daylight saving time.
 * @method        bool           isSunday()                                                                          Checks if the instance day is sunday.
 * @method        bool           isMonday()                                                                          Checks if the instance day is monday.
 * @method        bool           isTuesday()                                                                         Checks if the instance day is tuesday.
 * @method        bool           isWednesday()                                                                       Checks if the instance day is wednesday.
 * @method        bool           isThursday()                                                                        Checks if the instance day is thursday.
 * @method        bool           isFriday()                                                                          Checks if the instance day is friday.
 * @method        bool           isSaturday()                                                                        Checks if the instance day is saturday.
 * @method        bool           isSameYear(\DateTimeInterface $date = null)                                         Checks if the given date is in the same year as the instance. If null passed, compare to now (with the same timezone).
 * @method        bool           isCurrentYear()                                                                     Checks if the instance is in the same year as the current moment.
 * @method        bool           isNextYear()                                                                        Checks if the instance is in the same year as the current moment next year.
 * @method        bool           isLastYear()                                                                        Checks if the instance is in the same year as the current moment last year.
 * @method        bool           isSameWeek(\DateTimeInterface $date = null)                                         Checks if the given date is in the same week as the instance. If null passed, compare to now (with the same timezone).
 * @method        bool           isCurrentWeek()                                                                     Checks if the instance is in the same week as the current moment.
 * @method        bool           isNextWeek()                                                                        Checks if the instance is in the same week as the current moment next week.
 * @method        bool           isLastWeek()                                                                        Checks if the instance is in the same week as the current moment last week.
 * @method        bool           isSameDay(\DateTimeInterface $date = null)                                          Checks if the given date is in the same day as the instance. If null passed, compare to now (with the same timezone).
 * @method        bool           isCurrentDay()                                                                      Checks if the instance is in the same day as the current moment.
 * @method        bool           isNextDay()                                                                         Checks if the instance is in the same day as the current moment next day.
 * @method        bool           isLastDay()                                                                         Checks if the instance is in the same day as the current moment last day.
 * @method        bool           isSameHour(\DateTimeInterface $date = null)                                         Checks if the given date is in the same hour as the instance. If null passed, compare to now (with the same timezone).
 * @method        bool           isCurrentHour()                                                                     Checks if the instance is in the same hour as the current moment.
 * @method        bool           isNextHour()                                                                        Checks if the instance is in the same hour as the current moment next hour.
 * @method        bool           isLastHour()                                                                        Checks if the instance is in the same hour as the current moment last hour.
 * @method        bool           isSameMinute(\DateTimeInterface $date = null)                                       Checks if the given date is in the same minute as the instance. If null passed, compare to now (with the same timezone).
 * @method        bool           isCurrentMinute()                                                                   Checks if the instance is in the same minute as the current moment.
 * @method        bool           isNextMinute()                                                                      Checks if the instance is in the same minute as the current moment next minute.
 * @method        bool           isLastMinute()                                                                      Checks if the instance is in the same minute as the current moment last minute.
 * @method        bool           isSameSecond(\DateTimeInterface $date = null)                                       Checks if the given date is in the same second as the instance. If null passed, compare to now (with the same timezone).
 * @method        bool           isCurrentSecond()                                                                   Checks if the instance is in the same second as the current moment.
 * @method        bool           isNextSecond()                                                                      Checks if the instance is in the same second as the current moment next second.
 * @method        bool           isLastSecond()                                                                      Checks if the instance is in the same second as the current moment last second.
 * @method        bool           isSameMicro(\DateTimeInterface $date = null)                                        Checks if the given date is in the same microsecond as the instance. If null passed, compare to now (with the same timezone).
 * @method        bool           isCurrentMicro()                                                                    Checks if the instance is in the same microsecond as the current moment.
 * @method        bool           isNextMicro()                                                                       Checks if the instance is in the same microsecond as the current moment next microsecond.
 * @method        bool           isLastMicro()                                                                       Checks if the instance is in the same microsecond as the current moment last microsecond.
 * @method        bool           isSameMicrosecond(\DateTimeInterface $date = null)                                  Checks if the given date is in the same microsecond as the instance. If null passed, compare to now (with the same timezone).
 * @method        bool           isCurrentMicrosecond()                                                              Checks if the instance is in the same microsecond as the current moment.
 * @method        bool           isNextMicrosecond()                                                                 Checks if the instance is in the same microsecond as the current moment next microsecond.
 * @method        bool           isLastMicrosecond()                                                                 Checks if the instance is in the same microsecond as the current moment last microsecond.
 * @method        bool           isCurrentMonth()                                                                    Checks if the instance is in the same month as the current moment.
 * @method        bool           isNextMonth()                                                                       Checks if the instance is in the same month as the current moment next month.
 * @method        bool           isLastMonth()                                                                       Checks if the instance is in the same month as the current moment last month.
 * @method        bool           isCurrentQuarter()                                                                  Checks if the instance is in the same quarter as the current moment.
 * @method        bool           isNextQuarter()                                                                     Checks if the instance is in the same quarter as the current moment next quarter.
 * @method        bool           isLastQuarter()                                                                     Checks if the instance is in the same quarter as the current moment last quarter.
 * @method        bool           isSameDecade(\DateTimeInterface $date = null)                                       Checks if the given date is in the same decade as the instance. If null passed, compare to now (with the same timezone).
 * @method        bool           isCurrentDecade()                                                                   Checks if the instance is in the same decade as the current moment.
 * @method        bool           isNextDecade()                                                                      Checks if the instance is in the same decade as the current moment next decade.
 * @method        bool           isLastDecade()                                                                      Checks if the instance is in the same decade as the current moment last decade.
 * @method        bool           isSameCentury(\DateTimeInterface $date = null)                                      Checks if the given date is in the same century as the instance. If null passed, compare to now (with the same timezone).
 * @method        bool           isCurrentCentury()                                                                  Checks if the instance is in the same century as the current moment.
 * @method        bool           isNextCentury()                                                                     Checks if the instance is in the same century as the current moment next century.
 * @method        bool           isLastCentury()                                                                     Checks if the instance is in the same century as the current moment last century.
 * @method        bool           isSameMillennium(\DateTimeInterface $date = null)                                   Checks if the given date is in the same millennium as the instance. If null passed, compare to now (with the same timezone).
 * @method        bool           isCurrentMillennium()                                                               Checks if the instance is in the same millennium as the current moment.
 * @method        bool           isNextMillennium()                                                                  Checks if the instance is in the same millennium as the current moment next millennium.
 * @method        bool           isLastMillennium()                                                                  Checks if the instance is in the same millennium as the current moment last millennium.
 * @method        $this          years(int $value)                                                                   Set current instance year to the given value.
 * @method        $this          year(int $value)                                                                    Set current instance year to the given value.
 * @method        $this          setYears(int $value)                                                                Set current instance year to the given value.
 * @method        $this          setYear(int $value)                                                                 Set current instance year to the given value.
 * @method        $this          months(int $value)                                                                  Set current instance month to the given value.
 * @method        $this          month(int $value)                                                                   Set current instance month to the given value.
 * @method        $this          setMonths(int $value)                                                               Set current instance month to the given value.
 * @method        $this          setMonth(int $value)                                                                Set current instance month to the given value.
 * @method        $this          days(int $value)                                                                    Set current instance day to the given value.
 * @method        $this          day(int $value)                                                                     Set current instance day to the given value.
 * @method        $this          setDays(int $value)                                                                 Set current instance day to the given value.
 * @method        $this          setDay(int $value)                                                                  Set current instance day to the given value.
 * @method        $this          hours(int $value)                                                                   Set current instance hour to the given value.
 * @method        $this          hour(int $value)                                                                    Set current instance hour to the given value.
 * @method        $this          setHours(int $value)                                                                Set current instance hour to the given value.
 * @method        $this          setHour(int $value)                                                                 Set current instance hour to the given value.
 * @method        $this          minutes(int $value)                                                                 Set current instance minute to the given value.
 * @method        $this          minute(int $value)                                                                  Set current instance minute to the given value.
 * @method        $this          setMinutes(int $value)                                                              Set current instance minute to the given value.
 * @method        $this          setMinute(int $value)                                                               Set current instance minute to the given value.
 * @method        $this          seconds(int $value)                                                                 Set current instance second to the given value.
 * @method        $this          second(int $value)                                                                  Set current instance second to the given value.
 * @method        $this          setSeconds(int $value)                                                              Set current instance second to the given value.
 * @method        $this          setSecond(int $value)                                                               Set current instance second to the given value.
 * @method        $this          millis(int $value)                                                                  Set current instance millisecond to the given value.
 * @method        $this          milli(int $value)                                                                   Set current instance millisecond to the given value.
 * @method        $this          setMillis(int $value)                                                               Set current instance millisecond to the given value.
 * @method        $this          setMilli(int $value)                                                                Set current instance millisecond to the given value.
 * @method        $this          milliseconds(int $value)                                                            Set current instance millisecond to the given value.
 * @method        $this          millisecond(int $value)                                                             Set current instance millisecond to the given value.
 * @method        $this          setMilliseconds(int $value)                                                         Set current instance millisecond to the given value.
 * @method        $this          setMillisecond(int $value)                                                          Set current instance millisecond to the given value.
 * @method        $this          micros(int $value)                                                                  Set current instance microsecond to the given value.
 * @method        $this          micro(int $value)                                                                   Set current instance microsecond to the given value.
 * @method        $this          setMicros(int $value)                                                               Set current instance microsecond to the given value.
 * @method        $this          setMicro(int $value)                                                                Set current instance microsecond to the given value.
 * @method        $this          microseconds(int $value)                                                            Set current instance microsecond to the given value.
 * @method        $this          microsecond(int $value)                                                             Set current instance microsecond to the given value.
 * @method        $this          setMicroseconds(int $value)                                                         Set current instance microsecond to the given value.
 * @method        $this          setMicrosecond(int $value)                                                          Set current instance microsecond to the given value.
 * @method        $this          addYears(int $value = 1)                                                            Add years (the $value count passed in) to the instance (using date interval).
 * @method        $this          addYear()                                                                           Add one year to the instance (using date interval).
 * @method        $this          subYears(int $value = 1)                                                            Sub years (the $value count passed in) to the instance (using date interval).
 * @method        $this          subYear()                                                                           Sub one year to the instance (using date interval).
 * @method        $this          addYearsWithOverflow(int $value = 1)                                                Add years (the $value count passed in) to the instance (using date interval) with overflow explicitly allowed.
 * @method        $this          addYearWithOverflow()                                                               Add one year to the instance (using date interval) with overflow explicitly allowed.
 * @method        $this          subYearsWithOverflow(int $value = 1)                                                Sub years (the $value count passed in) to the instance (using date interval) with overflow explicitly allowed.
 * @method        $this          subYearWithOverflow()                                                               Sub one year to the instance (using date interval) with overflow explicitly allowed.
 * @method        $this          addYearsWithoutOverflow(int $value = 1)                                             Add years (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden.
 * @method        $this          addYearWithoutOverflow()                                                            Add one year to the instance (using date interval) with overflow explicitly forbidden.
 * @method        $this          subYearsWithoutOverflow(int $value = 1)                                             Sub years (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden.
 * @method        $this          subYearWithoutOverflow()                                                            Sub one year to the instance (using date interval) with overflow explicitly forbidden.
 * @method        $this          addYearsWithNoOverflow(int $value = 1)                                              Add years (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden.
 * @method        $this          addYearWithNoOverflow()                                                             Add one year to the instance (using date interval) with overflow explicitly forbidden.
 * @method        $this          subYearsWithNoOverflow(int $value = 1)                                              Sub years (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden.
 * @method        $this          subYearWithNoOverflow()                                                             Sub one year to the instance (using date interval) with overflow explicitly forbidden.
 * @method        $this          addYearsNoOverflow(int $value = 1)                                                  Add years (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden.
 * @method        $this          addYearNoOverflow()                                                                 Add one year to the instance (using date interval) with overflow explicitly forbidden.
 * @method        $this          subYearsNoOverflow(int $value = 1)                                                  Sub years (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden.
 * @method        $this          subYearNoOverflow()                                                                 Sub one year to the instance (using date interval) with overflow explicitly forbidden.
 * @method        $this          addMonths(int $value = 1)                                                           Add months (the $value count passed in) to the instance (using date interval).
 * @method        $this          addMonth()                                                                          Add one month to the instance (using date interval).
 * @method        $this          subMonths(int $value = 1)                                                           Sub months (the $value count passed in) to the instance (using date interval).
 * @method        $this          subMonth()                                                                          Sub one month to the instance (using date interval).
 * @method        $this          addMonthsWithOverflow(int $value = 1)                                               Add months (the $value count passed in) to the instance (using date interval) with overflow explicitly allowed.
 * @method        $this          addMonthWithOverflow()                                                              Add one month to the instance (using date interval) with overflow explicitly allowed.
 * @method        $this          subMonthsWithOverflow(int $value = 1)                                               Sub months (the $value count passed in) to the instance (using date interval) with overflow explicitly allowed.
 * @method        $this          subMonthWithOverflow()                                                              Sub one month to the instance (using date interval) with overflow explicitly allowed.
 * @method        $this          addMonthsWithoutOverflow(int $value = 1)                                            Add months (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden.
 * @method        $this          addMonthWithoutOverflow()                                                           Add one month to the instance (using date interval) with overflow explicitly forbidden.
 * @method        $this          subMonthsWithoutOverflow(int $value = 1)                                            Sub months (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden.
 * @method        $this          subMonthWithoutOverflow()                                                           Sub one month to the instance (using date interval) with overflow explicitly forbidden.
 * @method        $this          addMonthsWithNoOverflow(int $value = 1)                                             Add months (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden.
 * @method        $this          addMonthWithNoOverflow()                                                            Add one month to the instance (using date interval) with overflow explicitly forbidden.
 * @method        $this          subMonthsWithNoOverflow(int $value = 1)                                             Sub months (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden.
 * @method        $this          subMonthWithNoOverflow()                                                            Sub one month to the instance (using date interval) with overflow explicitly forbidden.
 * @method        $this          addMonthsNoOverflow(int $value = 1)                                                 Add months (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden.
 * @method        $this          addMonthNoOverflow()                                                                Add one month to the instance (using date interval) with overflow explicitly forbidden.
 * @method        $this          subMonthsNoOverflow(int $value = 1)                                                 Sub months (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden.
 * @method        $this          subMonthNoOverflow()                                                                Sub one month to the instance (using date interval) with overflow explicitly forbidden.
 * @method        $this          addDays(int $value = 1)                                                             Add days (the $value count passed in) to the instance (using date interval).
 * @method        $this          addDay()                                                                            Add one day to the instance (using date interval).
 * @method        $this          subDays(int $value = 1)                                                             Sub days (the $value count passed in) to the instance (using date interval).
 * @method        $this          subDay()                                                                            Sub one day to the instance (using date interval).
 * @method        $this          addHours(int $value = 1)                                                            Add hours (the $value count passed in) to the instance (using date interval).
 * @method        $this          addHour()                                                                           Add one hour to the instance (using date interval).
 * @method        $this          subHours(int $value = 1)                                                            Sub hours (the $value count passed in) to the instance (using date interval).
 * @method        $this          subHour()                                                                           Sub one hour to the instance (using date interval).
 * @method        $this          addMinutes(int $value = 1)                                                          Add minutes (the $value count passed in) to the instance (using date interval).
 * @method        $this          addMinute()                                                                         Add one minute to the instance (using date interval).
 * @method        $this          subMinutes(int $value = 1)                                                          Sub minutes (the $value count passed in) to the instance (using date interval).
 * @method        $this          subMinute()                                                                         Sub one minute to the instance (using date interval).
 * @method        $this          addSeconds(int $value = 1)                                                          Add seconds (the $value count passed in) to the instance (using date interval).
 * @method        $this          addSecond()                                                                         Add one second to the instance (using date interval).
 * @method        $this          subSeconds(int $value = 1)                                                          Sub seconds (the $value count passed in) to the instance (using date interval).
 * @method        $this          subSecond()                                                                         Sub one second to the instance (using date interval).
 * @method        $this          addMillis(int $value = 1)                                                           Add milliseconds (the $value count passed in) to the instance (using date interval).
 * @method        $this          addMilli()                                                                          Add one millisecond to the instance (using date interval).
 * @method        $this          subMillis(int $value = 1)                                                           Sub milliseconds (the $value count passed in) to the instance (using date interval).
 * @method        $this          subMilli()                                                                          Sub one millisecond to the instance (using date interval).
 * @method        $this          addMilliseconds(int $value = 1)                                                     Add milliseconds (the $value count passed in) to the instance (using date interval).
 * @method        $this          addMillisecond()                                                                    Add one millisecond to the instance (using date interval).
 * @method        $this          subMilliseconds(int $value = 1)                                                     Sub milliseconds (the $value count passed in) to the instance (using date interval).
 * @method        $this          subMillisecond()                                                                    Sub one millisecond to the instance (using date interval).
 * @method        $this          addMicros(int $value = 1)                                                           Add microseconds (the $value count passed in) to the instance (using date interval).
 * @method        $this          addMicro()                                                                          Add one microsecond to the instance (using date interval).
 * @method        $this          subMicros(int $value = 1)                                                           Sub microseconds (the $value count passed in) to the instance (using date interval).
 * @method        $this          subMicro()                                                                          Sub one microsecond to the instance (using date interval).
 * @method        $this          addMicroseconds(int $value = 1)                                                     Add microseconds (the $value count passed in) to the instance (using date interval).
 * @method        $this          addMicrosecond()                                                                    Add one microsecond to the instance (using date interval).
 * @method        $this          subMicroseconds(int $value = 1)                                                     Sub microseconds (the $value count passed in) to the instance (using date interval).
 * @method        $this          subMicrosecond()                                                                    Sub one microsecond to the instance (using date interval).
 * @method        $this          addMillennia(int $value = 1)                                                        Add millennia (the $value count passed in) to the instance (using date interval).
 * @method        $this          addMillennium()                                                                     Add one millennium to the instance (using date interval).
 * @method        $this          subMillennia(int $value = 1)                                                        Sub millennia (the $value count passed in) to the instance (using date interval).
 * @method        $this          subMillennium()                                                                     Sub one millennium to the instance (using date interval).
 * @method        $this          addMillenniaWithOverflow(int $value = 1)                                            Add millennia (the $value count passed in) to the instance (using date interval) with overflow explicitly allowed.
 * @method        $this          addMillenniumWithOverflow()                                                         Add one millennium to the instance (using date interval) with overflow explicitly allowed.
 * @method        $this          subMillenniaWithOverflow(int $value = 1)                                            Sub millennia (the $value count passed in) to the instance (using date interval) with overflow explicitly allowed.
 * @method        $this          subMillenniumWithOverflow()                                                         Sub one millennium to the instance (using date interval) with overflow explicitly allowed.
 * @method        $this          addMillenniaWithoutOverflow(int $value = 1)                                         Add millennia (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden.
 * @method        $this          addMillenniumWithoutOverflow()                                                      Add one millennium to the instance (using date interval) with overflow explicitly forbidden.
 * @method        $this          subMillenniaWithoutOverflow(int $value = 1)                                         Sub millennia (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden.
 * @method        $this          subMillenniumWithoutOverflow()                                                      Sub one millennium to the instance (using date interval) with overflow explicitly forbidden.
 * @method        $this          addMillenniaWithNoOverflow(int $value = 1)                                          Add millennia (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden.
 * @method        $this          addMillenniumWithNoOverflow()                                                       Add one millennium to the instance (using date interval) with overflow explicitly forbidden.
 * @method        $this          subMillenniaWithNoOverflow(int $value = 1)                                          Sub millennia (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden.
 * @method        $this          subMillenniumWithNoOverflow()                                                       Sub one millennium to the instance (using date interval) with overflow explicitly forbidden.
 * @method        $this          addMillenniaNoOverflow(int $value = 1)                                              Add millennia (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden.
 * @method        $this          addMillenniumNoOverflow()                                                           Add one millennium to the instance (using date interval) with overflow explicitly forbidden.
 * @method        $this          subMillenniaNoOverflow(int $value = 1)                                              Sub millennia (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden.
 * @method        $this          subMillenniumNoOverflow()                                                           Sub one millennium to the instance (using date interval) with overflow explicitly forbidden.
 * @method        $this          addCenturies(int $value = 1)                                                        Add centuries (the $value count passed in) to the instance (using date interval).
 * @method        $this          addCentury()                                                                        Add one century to the instance (using date interval).
 * @method        $this          subCenturies(int $value = 1)                                                        Sub centuries (the $value count passed in) to the instance (using date interval).
 * @method        $this          subCentury()                                                                        Sub one century to the instance (using date interval).
 * @method        $this          addCenturiesWithOverflow(int $value = 1)                                            Add centuries (the $value count passed in) to the instance (using date interval) with overflow explicitly allowed.
 * @method        $this          addCenturyWithOverflow()                                                            Add one century to the instance (using date interval) with overflow explicitly allowed.
 * @method        $this          subCenturiesWithOverflow(int $value = 1)                                            Sub centuries (the $value count passed in) to the instance (using date interval) with overflow explicitly allowed.
 * @method        $this          subCenturyWithOverflow()                                                            Sub one century to the instance (using date interval) with overflow explicitly allowed.
 * @method        $this          addCenturiesWithoutOverflow(int $value = 1)                                         Add centuries (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden.
 * @method        $this          addCenturyWithoutOverflow()                                                         Add one century to the instance (using date interval) with overflow explicitly forbidden.
 * @method        $this          subCenturiesWithoutOverflow(int $value = 1)                                         Sub centuries (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden.
 * @method        $this          subCenturyWithoutOverflow()                                                         Sub one century to the instance (using date interval) with overflow explicitly forbidden.
 * @method        $this          addCenturiesWithNoOverflow(int $value = 1)                                          Add centuries (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden.
 * @method        $this          addCenturyWithNoOverflow()                                                          Add one century to the instance (using date interval) with overflow explicitly forbidden.
 * @method        $this          subCenturiesWithNoOverflow(int $value = 1)                                          Sub centuries (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden.
 * @method        $this          subCenturyWithNoOverflow()                                                          Sub one century to the instance (using date interval) with overflow explicitly forbidden.
 * @method        $this          addCenturiesNoOverflow(int $value = 1)                                              Add centuries (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden.
 * @method        $this          addCenturyNoOverflow()                                                              Add one century to the instance (using date interval) with overflow explicitly forbidden.
 * @method        $this          subCenturiesNoOverflow(int $value = 1)                                              Sub centuries (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden.
 * @method        $this          subCenturyNoOverflow()                                                              Sub one century to the instance (using date interval) with overflow explicitly forbidden.
 * @method        $this          addDecades(int $value = 1)                                                          Add decades (the $value count passed in) to the instance (using date interval).
 * @method        $this          addDecade()                                                                         Add one decade to the instance (using date interval).
 * @method        $this          subDecades(int $value = 1)                                                          Sub decades (the $value count passed in) to the instance (using date interval).
 * @method        $this          subDecade()                                                                         Sub one decade to the instance (using date interval).
 * @method        $this          addDecadesWithOverflow(int $value = 1)                                              Add decades (the $value count passed in) to the instance (using date interval) with overflow explicitly allowed.
 * @method        $this          addDecadeWithOverflow()                                                             Add one decade to the instance (using date interval) with overflow explicitly allowed.
 * @method        $this          subDecadesWithOverflow(int $value = 1)                                              Sub decades (the $value count passed in) to the instance (using date interval) with overflow explicitly allowed.
 * @method        $this          subDecadeWithOverflow()                                                             Sub one decade to the instance (using date interval) with overflow explicitly allowed.
 * @method        $this          addDecadesWithoutOverflow(int $value = 1)                                           Add decades (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden.
 * @method        $this          addDecadeWithoutOverflow()                                                          Add one decade to the instance (using date interval) with overflow explicitly forbidden.
 * @method        $this          subDecadesWithoutOverflow(int $value = 1)                                           Sub decades (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden.
 * @method        $this          subDecadeWithoutOverflow()                                                          Sub one decade to the instance (using date interval) with overflow explicitly forbidden.
 * @method        $this          addDecadesWithNoOverflow(int $value = 1)                                            Add decades (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden.
 * @method        $this          addDecadeWithNoOverflow()                                                           Add one decade to the instance (using date interval) with overflow explicitly forbidden.
 * @method        $this          subDecadesWithNoOverflow(int $value = 1)                                            Sub decades (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden.
 * @method        $this          subDecadeWithNoOverflow()                                                           Sub one decade to the instance (using date interval) with overflow explicitly forbidden.
 * @method        $this          addDecadesNoOverflow(int $value = 1)                                                Add decades (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden.
 * @method        $this          addDecadeNoOverflow()                                                               Add one decade to the instance (using date interval) with overflow explicitly forbidden.
 * @method        $this          subDecadesNoOverflow(int $value = 1)                                                Sub decades (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden.
 * @method        $this          subDecadeNoOverflow()                                                               Sub one decade to the instance (using date interval) with overflow explicitly forbidden.
 * @method        $this          addQuarters(int $value = 1)                                                         Add quarters (the $value count passed in) to the instance (using date interval).
 * @method        $this          addQuarter()                                                                        Add one quarter to the instance (using date interval).
 * @method        $this          subQuarters(int $value = 1)                                                         Sub quarters (the $value count passed in) to the instance (using date interval).
 * @method        $this          subQuarter()                                                                        Sub one quarter to the instance (using date interval).
 * @method        $this          addQuartersWithOverflow(int $value = 1)                                             Add quarters (the $value count passed in) to the instance (using date interval) with overflow explicitly allowed.
 * @method        $this          addQuarterWithOverflow()                                                            Add one quarter to the instance (using date interval) with overflow explicitly allowed.
 * @method        $this          subQuartersWithOverflow(int $value = 1)                                             Sub quarters (the $value count passed in) to the instance (using date interval) with overflow explicitly allowed.
 * @method        $this          subQuarterWithOverflow()                                                            Sub one quarter to the instance (using date interval) with overflow explicitly allowed.
 * @method        $this          addQuartersWithoutOverflow(int $value = 1)                                          Add quarters (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden.
 * @method        $this          addQuarterWithoutOverflow()                                                         Add one quarter to the instance (using date interval) with overflow explicitly forbidden.
 * @method        $this          subQuartersWithoutOverflow(int $value = 1)                                          Sub quarters (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden.
 * @method        $this          subQuarterWithoutOverflow()                                                         Sub one quarter to the instance (using date interval) with overflow explicitly forbidden.
 * @method        $this          addQuartersWithNoOverflow(int $value = 1)                                           Add quarters (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden.
 * @method        $this          addQuarterWithNoOverflow()                                                          Add one quarter to the instance (using date interval) with overflow explicitly forbidden.
 * @method        $this          subQuartersWithNoOverflow(int $value = 1)                                           Sub quarters (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden.
 * @method        $this          subQuarterWithNoOverflow()                                                          Sub one quarter to the instance (using date interval) with overflow explicitly forbidden.
 * @method        $this          addQuartersNoOverflow(int $value = 1)                                               Add quarters (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden.
 * @method        $this          addQuarterNoOverflow()                                                              Add one quarter to the instance (using date interval) with overflow explicitly forbidden.
 * @method        $this          subQuartersNoOverflow(int $value = 1)                                               Sub quarters (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden.
 * @method        $this          subQuarterNoOverflow()                                                              Sub one quarter to the instance (using date interval) with overflow explicitly forbidden.
 * @method        $this          addWeeks(int $value = 1)                                                            Add weeks (the $value count passed in) to the instance (using date interval).
 * @method        $this          addWeek()                                                                           Add one week to the instance (using date interval).
 * @method        $this          subWeeks(int $value = 1)                                                            Sub weeks (the $value count passed in) to the instance (using date interval).
 * @method        $this          subWeek()                                                                           Sub one week to the instance (using date interval).
 * @method        $this          addWeekdays(int $value = 1)                                                         Add weekdays (the $value count passed in) to the instance (using date interval).
 * @method        $this          addWeekday()                                                                        Add one weekday to the instance (using date interval).
 * @method        $this          subWeekdays(int $value = 1)                                                         Sub weekdays (the $value count passed in) to the instance (using date interval).
 * @method        $this          subWeekday()                                                                        Sub one weekday to the instance (using date interval).
 * @method        $this          addRealMicros(int $value = 1)                                                       Add microseconds (the $value count passed in) to the instance (using timestamp).
 * @method        $this          addRealMicro()                                                                      Add one microsecond to the instance (using timestamp).
 * @method        $this          subRealMicros(int $value = 1)                                                       Sub microseconds (the $value count passed in) to the instance (using timestamp).
 * @method        $this          subRealMicro()                                                                      Sub one microsecond to the instance (using timestamp).
 * @method        $this          addRealMicroseconds(int $value = 1)                                                 Add microseconds (the $value count passed in) to the instance (using timestamp).
 * @method        $this          addRealMicrosecond()                                                                Add one microsecond to the instance (using timestamp).
 * @method        $this          subRealMicroseconds(int $value = 1)                                                 Sub microseconds (the $value count passed in) to the instance (using timestamp).
 * @method        $this          subRealMicrosecond()                                                                Sub one microsecond to the instance (using timestamp).
 * @method        $this          addRealMillis(int $value = 1)                                                       Add milliseconds (the $value count passed in) to the instance (using timestamp).
 * @method        $this          addRealMilli()                                                                      Add one millisecond to the instance (using timestamp).
 * @method        $this          subRealMillis(int $value = 1)                                                       Sub milliseconds (the $value count passed in) to the instance (using timestamp).
 * @method        $this          subRealMilli()                                                                      Sub one millisecond to the instance (using timestamp).
 * @method        $this          addRealMilliseconds(int $value = 1)                                                 Add milliseconds (the $value count passed in) to the instance (using timestamp).
 * @method        $this          addRealMillisecond()                                                                Add one millisecond to the instance (using timestamp).
 * @method        $this          subRealMilliseconds(int $value = 1)                                                 Sub milliseconds (the $value count passed in) to the instance (using timestamp).
 * @method        $this          subRealMillisecond()                                                                Sub one millisecond to the instance (using timestamp).
 * @method        $this          addRealSeconds(int $value = 1)                                                      Add seconds (the $value count passed in) to the instance (using timestamp).
 * @method        $this          addRealSecond()                                                                     Add one second to the instance (using timestamp).
 * @method        $this          subRealSeconds(int $value = 1)                                                      Sub seconds (the $value count passed in) to the instance (using timestamp).
 * @method        $this          subRealSecond()                                                                     Sub one second to the instance (using timestamp).
 * @method        $this          addRealMinutes(int $value = 1)                                                      Add minutes (the $value count passed in) to the instance (using timestamp).
 * @method        $this          addRealMinute()                                                                     Add one minute to the instance (using timestamp).
 * @method        $this          subRealMinutes(int $value = 1)                                                      Sub minutes (the $value count passed in) to the instance (using timestamp).
 * @method        $this          subRealMinute()                                                                     Sub one minute to the instance (using timestamp).
 * @method        $this          addRealHours(int $value = 1)                                                        Add hours (the $value count passed in) to the instance (using timestamp).
 * @method        $this          addRealHour()                                                                       Add one hour to the instance (using timestamp).
 * @method        $this          subRealHours(int $value = 1)                                                        Sub hours (the $value count passed in) to the instance (using timestamp).
 * @method        $this          subRealHour()                                                                       Sub one hour to the instance (using timestamp).
 * @method        $this          addRealDays(int $value = 1)                                                         Add days (the $value count passed in) to the instance (using timestamp).
 * @method        $this          addRealDay()                                                                        Add one day to the instance (using timestamp).
 * @method        $this          subRealDays(int $value = 1)                                                         Sub days (the $value count passed in) to the instance (using timestamp).
 * @method        $this          subRealDay()                                                                        Sub one day to the instance (using timestamp).
 * @method        $this          addRealWeeks(int $value = 1)                                                        Add weeks (the $value count passed in) to the instance (using timestamp).
 * @method        $this          addRealWeek()                                                                       Add one week to the instance (using timestamp).
 * @method        $this          subRealWeeks(int $value = 1)                                                        Sub weeks (the $value count passed in) to the instance (using timestamp).
 * @method        $this          subRealWeek()                                                                       Sub one week to the instance (using timestamp).
 * @method        $this          addRealMonths(int $value = 1)                                                       Add months (the $value count passed in) to the instance (using timestamp).
 * @method        $this          addRealMonth()                                                                      Add one month to the instance (using timestamp).
 * @method        $this          subRealMonths(int $value = 1)                                                       Sub months (the $value count passed in) to the instance (using timestamp).
 * @method        $this          subRealMonth()                                                                      Sub one month to the instance (using timestamp).
 * @method        $this          addRealQuarters(int $value = 1)                                                     Add quarters (the $value count passed in) to the instance (using timestamp).
 * @method        $this          addRealQuarter()                                                                    Add one quarter to the instance (using timestamp).
 * @method        $this          subRealQuarters(int $value = 1)                                                     Sub quarters (the $value count passed in) to the instance (using timestamp).
 * @method        $this          subRealQuarter()                                                                    Sub one quarter to the instance (using timestamp).
 * @method        $this          addRealYears(int $value = 1)                                                        Add years (the $value count passed in) to the instance (using timestamp).
 * @method        $this          addRealYear()                                                                       Add one year to the instance (using timestamp).
 * @method        $this          subRealYears(int $value = 1)                                                        Sub years (the $value count passed in) to the instance (using timestamp).
 * @method        $this          subRealYear()                                                                       Sub one year to the instance (using timestamp).
 * @method        $this          addRealDecades(int $value = 1)                                                      Add decades (the $value count passed in) to the instance (using timestamp).
 * @method        $this          addRealDecade()                                                                     Add one decade to the instance (using timestamp).
 * @method        $this          subRealDecades(int $value = 1)                                                      Sub decades (the $value count passed in) to the instance (using timestamp).
 * @method        $this          subRealDecade()                                                                     Sub one decade to the instance (using timestamp).
 * @method        $this          addRealCenturies(int $value = 1)                                                    Add centuries (the $value count passed in) to the instance (using timestamp).
 * @method        $this          addRealCentury()                                                                    Add one century to the instance (using timestamp).
 * @method        $this          subRealCenturies(int $value = 1)                                                    Sub centuries (the $value count passed in) to the instance (using timestamp).
 * @method        $this          subRealCentury()                                                                    Sub one century to the instance (using timestamp).
 * @method        $this          addRealMillennia(int $value = 1)                                                    Add millennia (the $value count passed in) to the instance (using timestamp).
 * @method        $this          addRealMillennium()                                                                 Add one millennium to the instance (using timestamp).
 * @method        $this          subRealMillennia(int $value = 1)                                                    Sub millennia (the $value count passed in) to the instance (using timestamp).
 * @method        $this          subRealMillennium()                                                                 Sub one millennium to the instance (using timestamp).
 * @method        $this          roundYear(float $precision = 1, string $function = "round")                         Round the current instance year with given precision using the given function.
 * @method        $this          roundYears(float $precision = 1, string $function = "round")                        Round the current instance year with given precision using the given function.
 * @method        $this          floorYear(float $precision = 1)                                                     Truncate the current instance year with given precision.
 * @method        $this          floorYears(float $precision = 1)                                                    Truncate the current instance year with given precision.
 * @method        $this          ceilYear(float $precision = 1)                                                      Ceil the current instance year with given precision.
 * @method        $this          ceilYears(float $precision = 1)                                                     Ceil the current instance year with given precision.
 * @method        $this          roundMonth(float $precision = 1, string $function = "round")                        Round the current instance month with given precision using the given function.
 * @method        $this          roundMonths(float $precision = 1, string $function = "round")                       Round the current instance month with given precision using the given function.
 * @method        $this          floorMonth(float $precision = 1)                                                    Truncate the current instance month with given precision.
 * @method        $this          floorMonths(float $precision = 1)                                                   Truncate the current instance month with given precision.
 * @method        $this          ceilMonth(float $precision = 1)                                                     Ceil the current instance month with given precision.
 * @method        $this          ceilMonths(float $precision = 1)                                                    Ceil the current instance month with given precision.
 * @method        $this          roundDay(float $precision = 1, string $function = "round")                          Round the current instance day with given precision using the given function.
 * @method        $this          roundDays(float $precision = 1, string $function = "round")                         Round the current instance day with given precision using the given function.
 * @method        $this          floorDay(float $precision = 1)                                                      Truncate the current instance day with given precision.
 * @method        $this          floorDays(float $precision = 1)                                                     Truncate the current instance day with given precision.
 * @method        $this          ceilDay(float $precision = 1)                                                       Ceil the current instance day with given precision.
 * @method        $this          ceilDays(float $precision = 1)                                                      Ceil the current instance day with given precision.
 * @method        $this          roundHour(float $precision = 1, string $function = "round")                         Round the current instance hour with given precision using the given function.
 * @method        $this          roundHours(float $precision = 1, string $function = "round")                        Round the current instance hour with given precision using the given function.
 * @method        $this          floorHour(float $precision = 1)                                                     Truncate the current instance hour with given precision.
 * @method        $this          floorHours(float $precision = 1)                                                    Truncate the current instance hour with given precision.
 * @method        $this          ceilHour(float $precision = 1)                                                      Ceil the current instance hour with given precision.
 * @method        $this          ceilHours(float $precision = 1)                                                     Ceil the current instance hour with given precision.
 * @method        $this          roundMinute(float $precision = 1, string $function = "round")                       Round the current instance minute with given precision using the given function.
 * @method        $this          roundMinutes(float $precision = 1, string $function = "round")                      Round the current instance minute with given precision using the given function.
 * @method        $this          floorMinute(float $precision = 1)                                                   Truncate the current instance minute with given precision.
 * @method        $this          floorMinutes(float $precision = 1)                                                  Truncate the current instance minute with given precision.
 * @method        $this          ceilMinute(float $precision = 1)                                                    Ceil the current instance minute with given precision.
 * @method        $this          ceilMinutes(float $precision = 1)                                                   Ceil the current instance minute with given precision.
 * @method        $this          roundSecond(float $precision = 1, string $function = "round")                       Round the current instance second with given precision using the given function.
 * @method        $this          roundSeconds(float $precision = 1, string $function = "round")                      Round the current instance second with given precision using the given function.
 * @method        $this          floorSecond(float $precision = 1)                                                   Truncate the current instance second with given precision.
 * @method        $this          floorSeconds(float $precision = 1)                                                  Truncate the current instance second with given precision.
 * @method        $this          ceilSecond(float $precision = 1)                                                    Ceil the current instance second with given precision.
 * @method        $this          ceilSeconds(float $precision = 1)                                                   Ceil the current instance second with given precision.
 * @method        $this          roundMillennium(float $precision = 1, string $function = "round")                   Round the current instance millennium with given precision using the given function.
 * @method        $this          roundMillennia(float $precision = 1, string $function = "round")                    Round the current instance millennium with given precision using the given function.
 * @method        $this          floorMillennium(float $precision = 1)                                               Truncate the current instance millennium with given precision.
 * @method        $this          floorMillennia(float $precision = 1)                                                Truncate the current instance millennium with given precision.
 * @method        $this          ceilMillennium(float $precision = 1)                                                Ceil the current instance millennium with given precision.
 * @method        $this          ceilMillennia(float $precision = 1)                                                 Ceil the current instance millennium with given precision.
 * @method        $this          roundCentury(float $precision = 1, string $function = "round")                      Round the current instance century with given precision using the given function.
 * @method        $this          roundCenturies(float $precision = 1, string $function = "round")                    Round the current instance century with given precision using the given function.
 * @method        $this          floorCentury(float $precision = 1)                                                  Truncate the current instance century with given precision.
 * @method        $this          floorCenturies(float $precision = 1)                                                Truncate the current instance century with given precision.
 * @method        $this          ceilCentury(float $precision = 1)                                                   Ceil the current instance century with given precision.
 * @method        $this          ceilCenturies(float $precision = 1)                                                 Ceil the current instance century with given precision.
 * @method        $this          roundDecade(float $precision = 1, string $function = "round")                       Round the current instance decade with given precision using the given function.
 * @method        $this          roundDecades(float $precision = 1, string $function = "round")                      Round the current instance decade with given precision using the given function.
 * @method        $this          floorDecade(float $precision = 1)                                                   Truncate the current instance decade with given precision.
 * @method        $this          floorDecades(float $precision = 1)                                                  Truncate the current instance decade with given precision.
 * @method        $this          ceilDecade(float $precision = 1)                                                    Ceil the current instance decade with given precision.
 * @method        $this          ceilDecades(float $precision = 1)                                                   Ceil the current instance decade with given precision.
 * @method        $this          roundQuarter(float $precision = 1, string $function = "round")                      Round the current instance quarter with given precision using the given function.
 * @method        $this          roundQuarters(float $precision = 1, string $function = "round")                     Round the current instance quarter with given precision using the given function.
 * @method        $this          floorQuarter(float $precision = 1)                                                  Truncate the current instance quarter with given precision.
 * @method        $this          floorQuarters(float $precision = 1)                                                 Truncate the current instance quarter with given precision.
 * @method        $this          ceilQuarter(float $precision = 1)                                                   Ceil the current instance quarter with given precision.
 * @method        $this          ceilQuarters(float $precision = 1)                                                  Ceil the current instance quarter with given precision.
 * @method        $this          roundMillisecond(float $precision = 1, string $function = "round")                  Round the current instance millisecond with given precision using the given function.
 * @method        $this          roundMilliseconds(float $precision = 1, string $function = "round")                 Round the current instance millisecond with given precision using the given function.
 * @method        $this          floorMillisecond(float $precision = 1)                                              Truncate the current instance millisecond with given precision.
 * @method        $this          floorMilliseconds(float $precision = 1)                                             Truncate the current instance millisecond with given precision.
 * @method        $this          ceilMillisecond(float $precision = 1)                                               Ceil the current instance millisecond with given precision.
 * @method        $this          ceilMilliseconds(float $precision = 1)                                              Ceil the current instance millisecond with given precision.
 * @method        $this          roundMicrosecond(float $precision = 1, string $function = "round")                  Round the current instance microsecond with given precision using the given function.
 * @method        $this          roundMicroseconds(float $precision = 1, string $function = "round")                 Round the current instance microsecond with given precision using the given function.
 * @method        $this          floorMicrosecond(float $precision = 1)                                              Truncate the current instance microsecond with given precision.
 * @method        $this          floorMicroseconds(float $precision = 1)                                             Truncate the current instance microsecond with given precision.
 * @method        $this          ceilMicrosecond(float $precision = 1)                                               Ceil the current instance microsecond with given precision.
 * @method        $this          ceilMicroseconds(float $precision = 1)                                              Ceil the current instance microsecond with given precision.
 * @method        string         shortAbsoluteDiffForHumans(\DateTimeInterface $other = null, int $parts = 1)        Get the difference (short format, 'Absolute' mode) in a human readable format in the current locale. ($other and $parts parameters can be swapped.)
 * @method        string         longAbsoluteDiffForHumans(\DateTimeInterface $other = null, int $parts = 1)         Get the difference (long format, 'Absolute' mode) in a human readable format in the current locale. ($other and $parts parameters can be swapped.)
 * @method        string         shortRelativeDiffForHumans(\DateTimeInterface $other = null, int $parts = 1)        Get the difference (short format, 'Relative' mode) in a human readable format in the current locale. ($other and $parts parameters can be swapped.)
 * @method        string         longRelativeDiffForHumans(\DateTimeInterface $other = null, int $parts = 1)         Get the difference (long format, 'Relative' mode) in a human readable format in the current locale. ($other and $parts parameters can be swapped.)
 * @method        string         shortRelativeToNowDiffForHumans(\DateTimeInterface $other = null, int $parts = 1)   Get the difference (short format, 'RelativeToNow' mode) in a human readable format in the current locale. ($other and $parts parameters can be swapped.)
 * @method        string         longRelativeToNowDiffForHumans(\DateTimeInterface $other = null, int $parts = 1)    Get the difference (long format, 'RelativeToNow' mode) in a human readable format in the current locale. ($other and $parts parameters can be swapped.)
 * @method        string         shortRelativeToOtherDiffForHumans(\DateTimeInterface $other = null, int $parts = 1) Get the difference (short format, 'RelativeToOther' mode) in a human readable format in the current locale. ($other and $parts parameters can be swapped.)
 * @method        string         longRelativeToOtherDiffForHumans(\DateTimeInterface $other = null, int $parts = 1)  Get the difference (long format, 'RelativeToOther' mode) in a human readable format in the current locale. ($other and $parts parameters can be swapped.)
 *
 * </autodoc>
 */
trait Date
{
    use Boundaries;
    use Comparison;
    use Converter;
    use Creator;
    use Difference;
    use Macro;
    use Modifiers;
    use Mutability;
    use Options;
    use Rounding;
    use Serialization;
    use Test;
    use Timestamp;
    use Units;
    use Week;

    /**
     * Names of days of the week.
     *
     * @var array
     */
    protected static $days = [
        // @call isDayOfWeek
        self::SUNDAY => 'Sunday',
        // @call isDayOfWeek
        self::MONDAY => 'Monday',
        // @call isDayOfWeek
        self::TUESDAY => 'Tuesday',
        // @call isDayOfWeek
        self::WEDNESDAY => 'Wednesday',
        // @call isDayOfWeek
        self::THURSDAY => 'Thursday',
        // @call isDayOfWeek
        self::FRIDAY => 'Friday',
        // @call isDayOfWeek
        self::SATURDAY => 'Saturday',
    ];

    /**
     * Will UTF8 encoding be used to print localized date/time ?
     *
     * @var bool
     */
    protected static $utf8 = false;

    /**
     * List of unit and magic methods associated as doc-comments.
     *
     * @var array
     */
    protected static $units = [
        // @call setUnit
        // @call addUnit
        'year',
        // @call setUnit
        // @call addUnit
        'month',
        // @call setUnit
        // @call addUnit
        'day',
        // @call setUnit
        // @call addUnit
        'hour',
        // @call setUnit
        // @call addUnit
        'minute',
        // @call setUnit
        // @call addUnit
        'second',
        // @call setUnit
        // @call addUnit
        'milli',
        // @call setUnit
        // @call addUnit
        'millisecond',
        // @call setUnit
        // @call addUnit
        'micro',
        // @call setUnit
        // @call addUnit
        'microsecond',
    ];

    /**
     * Creates a DateTimeZone from a string, DateTimeZone or integer offset.
     *
     * @param \DateTimeZone|string|int|null $object     original value to get CarbonTimeZone from it.
     * @param \DateTimeZone|string|int|null $objectDump dump of the object for error messages.
     *
     * @throws \InvalidArgumentException
     *
     * @return CarbonTimeZone|false
     */
    protected static function safeCreateDateTimeZone($object, $objectDump = null)
    {
        return CarbonTimeZone::instance($object, $objectDump);
    }

    /**
     * Creates a DateTimeZone from a string, DateTimeZone or integer offset then convert it as region timezone
     * if integer.
     *
     * @param \DateTimeZone|string|int|null $object
     * @param \DateTimeZone|string|int|null $originalObject if different
     *
     * @throws \InvalidArgumentException
     *
     * @return CarbonTimeZone|false
     */
    protected function autoDetectTimeZone($object, $originalObject = null)
    {
        /** @var CarbonTimeZone $timezone */
        $timezone = CarbonTimeZone::instance($object);
        if ($timezone && is_int($originalObject ?: $object)) {
            $timezone = $timezone->toRegionTimeZone($this);
        }

        return $timezone;
    }

    /**
     * Get the TimeZone associated with the Carbon instance (as CarbonTimeZone).
     *
     * @return CarbonTimeZone
     *
     * @link http://php.net/manual/en/datetime.gettimezone.php
     */
    public function getTimezone()
    {
        return CarbonTimeZone::instance(parent::getTimezone());
    }

    /**
     * List of minimum and maximums for each unit.
     *
     * @return array
     */
    protected static function getRangesByUnit()
    {
        return [
            // @call roundUnit
            'year' => [1, 9999],
            // @call roundUnit
            'month' => [1, static::MONTHS_PER_YEAR],
            // @call roundUnit
            'day' => [1, 31],
            // @call roundUnit
            'hour' => [0, static::HOURS_PER_DAY - 1],
            // @call roundUnit
            'minute' => [0, static::MINUTES_PER_HOUR - 1],
            // @call roundUnit
            'second' => [0, static::SECONDS_PER_MINUTE - 1],
        ];
    }

    /**
     * Get a copy of the instance.
     *
     * @return static|CarbonInterface
     */
    public function copy()
    {
        return clone $this;
    }

    /**
     * @alias copy
     *
     * Get a copy of the instance.
     *
     * @return static|CarbonInterface
     */
    public function clone()
    {
        return clone $this;
    }

    /**
     * Returns a present instance in the same timezone.
     *
     * @return static|CarbonInterface
     */
    public function nowWithSameTz()
    {
        return static::now($this->getTimezone());
    }

    /**
     * Throws an exception if the given object is not a DateTime and does not implement DateTimeInterface.
     *
     * @param mixed        $date
     * @param string|array $other
     *
     * @throws \InvalidArgumentException
     */
    protected static function expectDateTime($date, $other = [])
    {
        $message = 'Expected ';
        foreach ((array) $other as $expect) {
            $message .= "$expect, ";
        }

        if (!$date instanceof DateTime && !$date instanceof DateTimeInterface) {
            throw new InvalidArgumentException(
                $message.'DateTime or DateTimeInterface, '.
                (is_object($date) ? get_class($date) : gettype($date)).' given'
            );
        }
    }

    /**
     * Return the Carbon instance passed through, a now instance in the same timezone
     * if null given or parse the input if string given.
     *
     * @param \Carbon\Carbon|\DateTimeInterface|string|null $date
     *
     * @return static|CarbonInterface
     */
    protected function resolveCarbon($date = null)
    {
        if (!$date) {
            return $this->nowWithSameTz();
        }

        if (is_string($date)) {
            return static::parse($date, $this->getTimezone());
        }

        static::expectDateTime($date, ['null', 'string']);

        return $date instanceof self ? $date : static::instance($date);
    }

    ///////////////////////////////////////////////////////////////////
    ///////////////////////// GETTERS AND SETTERS /////////////////////
    ///////////////////////////////////////////////////////////////////

    /**
     * Get a part of the Carbon object
     *
     * @param string $name
     *
     * @throws InvalidArgumentException|ReflectionException
     *
     * @return string|int|bool|\DateTimeZone|null
     */
    public function __get($name)
    {
        return $this->get($name);
    }

    /**
     * Get a part of the Carbon object
     *
     * @param string $name
     *
     * @throws InvalidArgumentException|ReflectionException
     *
     * @return string|int|bool|\DateTimeZone|null
     */
    public function get($name)
    {
        static $formats = [
            // @property int
            'year' => 'Y',
            // @property int
            'yearIso' => 'o',
            // @property int
            // @call isSameUnit
            'month' => 'n',
            // @property int
            'day' => 'j',
            // @property int
            'hour' => 'G',
            // @property int
            'minute' => 'i',
            // @property int
            'second' => 's',
            // @property int
            'micro' => 'u',
            // @property int
            'microsecond' => 'u',
            // @property-read int 0 (for Sunday) through 6 (for Saturday)
            'dayOfWeek' => 'w',
            // @property-read int 1 (for Monday) through 7 (for Sunday)
            'dayOfWeekIso' => 'N',
            // @property-read int ISO-8601 week number of year, weeks starting on Monday
            'weekOfYear' => 'W',
            // @property-read int number of days in the given month
            'daysInMonth' => 't',
            // @property int seconds since the Unix Epoch
            'timestamp' => 'U',
            // @property-read string "am"/"pm" (Ante meridiem or Post meridiem latin lowercase mark)
            'latinMeridiem' => 'a',
            // @property-read string "AM"/"PM" (Ante meridiem or Post meridiem latin uppercase mark)
            'latinUpperMeridiem' => 'A',
            // @property string the day of week in English
            'englishDayOfWeek' => 'l',
            // @property string the abbreviated day of week in English
            'shortEnglishDayOfWeek' => 'D',
            // @property string the day of week in English
            'englishMonth' => 'F',
            // @property string the abbreviated day of week in English
            'shortEnglishMonth' => 'M',
            // @property string the day of week in current locale LC_TIME
            'localeDayOfWeek' => '%A',
            // @property string the abbreviated day of week in current locale LC_TIME
            'shortLocaleDayOfWeek' => '%a',
            // @property string the month in current locale LC_TIME
            'localeMonth' => '%B',
            // @property string the abbreviated month in current locale LC_TIME
            'shortLocaleMonth' => '%b',
        ];

        switch (true) {
            case isset($formats[$name]):
                $format = $formats[$name];
                $method = substr($format, 0, 1) === '%' ? 'formatLocalized' : 'rawFormat';
                $value = $this->$method($format);

                return is_numeric($value) ? (int) $value : $value;

            // @property-read string long name of weekday translated according to Carbon locale, in english if no translation available for current language
            case $name === 'dayName':
                return $this->getTranslatedDayName();
            // @property-read string short name of weekday translated according to Carbon locale, in english if no translation available for current language
            case $name === 'shortDayName':
                return $this->getTranslatedShortDayName();
            // @property-read string very short name of weekday translated according to Carbon locale, in english if no translation available for current language
            case $name === 'minDayName':
                return $this->getTranslatedMinDayName();
            // @property-read string long name of month translated according to Carbon locale, in english if no translation available for current language
            case $name === 'monthName':
                return $this->getTranslatedMonthName();
            // @property-read string short name of month translated according to Carbon locale, in english if no translation available for current language
            case $name === 'shortMonthName':
                return $this->getTranslatedShortMonthName();
            // @property-read string lowercase meridiem mark translated according to Carbon locale, in latin if no translation available for current language
            case $name === 'meridiem':
                return $this->meridiem(true);
            // @property-read string uppercase meridiem mark translated according to Carbon locale, in latin if no translation available for current language
            case $name === 'upperMeridiem':
                return $this->meridiem();
            // @property-read int current hour from 1 to 24
            case $name === 'noZeroHour':
                return $this->hour ?: 24;
            // @property int
            case $name === 'milliseconds':
                // @property int
            case $name === 'millisecond':
            // @property int
            case $name === 'milli':
                return (int) floor($this->rawFormat('u') / 1000);

            // @property int 1 through 53
            case $name === 'week':
                return (int) $this->week();

            // @property int 1 through 53
            case $name === 'isoWeek':
                return (int) $this->isoWeek();

            // @property int year according to week format
            case $name === 'weekYear':
                return (int) $this->weekYear();

            // @property int year according to ISO week format
            case $name === 'isoWeekYear':
                return (int) $this->isoWeekYear();

            // @property-read int 51 through 53
            case $name === 'weeksInYear':
                return (int) $this->weeksInYear();

            // @property-read int 51 through 53
            case $name === 'isoWeeksInYear':
                return (int) $this->isoWeeksInYear();

            // @property-read int 1 through 5
            case $name === 'weekOfMonth':
                return (int) ceil($this->day / static::DAYS_PER_WEEK);

            // @property-read int 1 through 5
            case $name === 'weekNumberInMonth':
                return (int) ceil(($this->day + $this->copy()->startOfMonth()->dayOfWeekIso - 1) / static::DAYS_PER_WEEK);

            // @property-read int 0 through 6
            case $name === 'firstWeekDay':
                return $this->localTranslator ? ($this->getTranslationMessage('first_day_of_week') ?? 0) : static::getWeekStartsAt();

            // @property-read int 0 through 6
            case $name === 'lastWeekDay':
                return $this->localTranslator ? (($this->getTranslationMessage('first_day_of_week') ?? 0) + static::DAYS_PER_WEEK - 1) % static::DAYS_PER_WEEK : static::getWeekEndsAt();

            // @property int 1 through 366
            case $name === 'dayOfYear':
                return 1 + intval($this->rawFormat('z'));

            // @property-read int 365 or 366
            case $name === 'daysInYear':
                return $this->isLeapYear() ? 366 : 365;

            // @property int does a diffInYears() with default parameters
            case $name === 'age':
                return $this->diffInYears();

            // @property-read int the quarter of this instance, 1 - 4
            // @call isSameUnit
            case $name === 'quarter':
                return (int) ceil($this->month / static::MONTHS_PER_QUARTER);

            // @property-read int the decade of this instance
            // @call isSameUnit
            case $name === 'decade':
                return (int) ceil($this->year / static::YEARS_PER_DECADE);

            // @property-read int the century of this instance
            // @call isSameUnit
            case $name === 'century':
                $factor = 1;
                $year = $this->year;
                if ($year < 0) {
                    $year = -$year;
                    $factor = -1;
                }

                return (int) ($factor * ceil($year / static::YEARS_PER_CENTURY));

            // @property-read int the millennium of this instance
            // @call isSameUnit
            case $name === 'millennium':
                $factor = 1;
                $year = $this->year;
                if ($year < 0) {
                    $year = -$year;
                    $factor = -1;
                }

                return (int) ($factor * ceil($year / static::YEARS_PER_MILLENNIUM));

            // @property int the timezone offset in seconds from UTC
            case $name === 'offset':
                return $this->getOffset();

            // @property int the timezone offset in minutes from UTC
            case $name === 'offsetMinutes':
                return $this->getOffset() / static::SECONDS_PER_MINUTE;

            // @property int the timezone offset in hours from UTC
            case $name === 'offsetHours':
                return $this->getOffset() / static::SECONDS_PER_MINUTE / static::MINUTES_PER_HOUR;

            // @property-read bool daylight savings time indicator, true if DST, false otherwise
            case $name === 'dst':
                return $this->rawFormat('I') === '1';

            // @property-read bool checks if the timezone is local, true if local, false otherwise
            case $name === 'local':
                return $this->getOffset() === $this->copy()->setTimezone(date_default_timezone_get())->getOffset();

            // @property-read bool checks if the timezone is UTC, true if UTC, false otherwise
            case $name === 'utc':
                return $this->getOffset() === 0;

            // @property CarbonTimeZone $timezone the current timezone
            // @property CarbonTimeZone $tz alias of $timezone
            case $name === 'timezone' || $name === 'tz':
                return CarbonTimeZone::instance($this->getTimezone());

            // @property-read string $timezoneName the current timezone name
            // @property-read string $tzName alias of $timezoneName
            case $name === 'timezoneName' || $name === 'tzName':
                return $this->getTimezone()->getName();

            // @property-read string $timezoneAbbreviatedName the current timezone abbreviated name
            // @property-read string $tzAbbrName alias of $timezoneAbbreviatedName
            case $name === 'timezoneAbbreviatedName' || $name === 'tzAbbrName':
                return CarbonTimeZone::instance($this->getTimezone())->getAbbr($this->dst);

            // @property-read string locale of the current instance
            case $name === 'locale':
                return $this->getLocalTranslator()->getLocale();

            default:
                if (static::hasMacro($macro = 'get'.ucfirst($name))) {
                    return $this->$macro();
                }

                throw new InvalidArgumentException(sprintf("Unknown getter '%s'", $name));
        }
    }

    /**
     * Check if an attribute exists on the object
     *
     * @param string $name
     *
     * @return bool
     */
    public function __isset($name)
    {
        try {
            $this->__get($name);
        } catch (InvalidArgumentException | ReflectionException $e) {
            return false;
        }

        return true;
    }

    /**
     * Set a part of the Carbon object
     *
     * @param string                   $name
     * @param string|int|\DateTimeZone $value
     *
     * @throws InvalidArgumentException|ReflectionException
     *
     * @return void
     */
    public function __set($name, $value)
    {
        $this->set($name, $value);
    }

    /**
     * Set a part of the Carbon object
     *
     * @param string|array             $name
     * @param string|int|\DateTimeZone $value
     *
     * @throws InvalidArgumentException|ReflectionException
     *
     * @return $this
     */
    public function set($name, $value = null)
    {
        if ($this->isImmutable()) {
            throw new \RuntimeException(sprintf(
                '%s class is immutable.', static::class
            ));
        }

        if (is_array($name)) {
            foreach ($name as $_name => $value) {
                $this->set($_name, $value);
            }

            return $this;
        }

        switch ($name) {
            case 'milliseconds':
            case 'millisecond':
            case 'milli':
            case 'microseconds':
            case 'microsecond':
            case 'micro':
                if (substr($name, 0, 5) === 'milli') {
                    $value *= 1000;
                }
                while ($value < 0) {
                    $this->subSecond();
                    $value += static::MICROSECONDS_PER_SECOND;
                }
                while ($value >= static::MICROSECONDS_PER_SECOND) {
                    $this->addSecond();
                    $value -= static::MICROSECONDS_PER_SECOND;
                }
                $this->modify($this->rawFormat('H:i:s.').str_pad(round($value), 6, '0', STR_PAD_LEFT));
                break;

            case 'year':
            case 'month':
            case 'day':
            case 'hour':
            case 'minute':
            case 'second':
                [$year, $month, $day, $hour, $minute, $second] = explode('-', $this->rawFormat('Y-n-j-G-i-s'));
                $$name = $value;
                $this->setDateTime($year, $month, $day, $hour, $minute, $second);
                break;

            case 'week':
                return $this->week($value);

            case 'isoWeek':
                return $this->isoWeek($value);

            case 'weekYear':
                return $this->weekYear($value);

            case 'isoWeekYear':
                return $this->isoWeekYear($value);

            case 'dayOfYear':
                return $this->addDays($value - $this->dayOfYear);

            case 'timestamp':
                parent::setTimestamp($value);
                break;

            case 'offset':
                $this->setTimezone(static::safeCreateDateTimeZone($value / static::SECONDS_PER_MINUTE / static::MINUTES_PER_HOUR));
                break;

            case 'offsetMinutes':
                $this->setTimezone(static::safeCreateDateTimeZone($value / static::MINUTES_PER_HOUR));
                break;

            case 'offsetHours':
                $this->setTimezone(static::safeCreateDateTimeZone($value));
                break;

            case 'timezone':
            case 'tz':
                $this->setTimezone($value);
                break;

            default:
                if (static::hasMacro($macro = 'set'.ucfirst($name))) {
                    $this->$macro($value);

                    break;
                }

                if ($this->localStrictModeEnabled ?? static::isStrictModeEnabled()) {
                    throw new InvalidArgumentException(sprintf("Unknown setter '%s'", $name));
                }

                $this->$name = $value;
        }

        return $this;
    }

    protected function getTranslatedFormByRegExp($baseKey, $keySuffix, $context, $subKey, $defaultValue)
    {
        $key = $baseKey.$keySuffix;
        $standaloneKey = "${key}_standalone";
        $baseTranslation = $this->getTranslationMessage($key);

        if ($baseTranslation instanceof Closure) {
            return $baseTranslation($this, $context, $subKey) ?: $defaultValue;
        }

        if (
            $this->getTranslationMessage("$standaloneKey.$subKey") &&
            (!$context || ($regExp = $this->getTranslationMessage("${baseKey}_regexp")) && !preg_match($regExp, $context))
        ) {
            $key = $standaloneKey;
        }

        return $this->getTranslationMessage("$key.$subKey", null, $defaultValue);
    }

    /**
     * Get the translation of the current week day name (with context for languages with multiple forms).
     *
     * @param string|null $context      whole format string
     * @param string      $keySuffix    "", "_short" or "_min"
     * @param string|null $defaultValue default value if translation missing
     *
     * @return string
     */
    public function getTranslatedDayName($context = null, $keySuffix = '', $defaultValue = null)
    {
        return $this->getTranslatedFormByRegExp('weekdays', $keySuffix, $context, $this->dayOfWeek, $defaultValue ?: $this->englishDayOfWeek);
    }

    /**
     * Get the translation of the current short week day name (with context for languages with multiple forms).
     *
     * @param string|null $context whole format string
     *
     * @return string
     */
    public function getTranslatedShortDayName($context = null)
    {
        return $this->getTranslatedDayName($context, '_short', $this->shortEnglishDayOfWeek);
    }

    /**
     * Get the translation of the current abbreviated week day name (with context for languages with multiple forms).
     *
     * @param string|null $context whole format string
     *
     * @return string
     */
    public function getTranslatedMinDayName($context = null)
    {
        return $this->getTranslatedDayName($context, '_min', $this->shortEnglishDayOfWeek);
    }

    /**
     * Get the translation of the current month day name (with context for languages with multiple forms).
     *
     * @param string|null $context      whole format string
     * @param string      $keySuffix    "" or "_short"
     * @param string|null $defaultValue default value if translation missing
     *
     * @return string
     */
    public function getTranslatedMonthName($context = null, $keySuffix = '', $defaultValue = null)
    {
        return $this->getTranslatedFormByRegExp('months', $keySuffix, $context, $this->month - 1, $defaultValue ?: $this->englishMonth);
    }

    /**
     * Get the translation of the current short month day name (with context for languages with multiple forms).
     *
     * @param string|null $context whole format string
     *
     * @return string
     */
    public function getTranslatedShortMonthName($context = null)
    {
        return $this->getTranslatedMonthName($context, '_short', $this->shortEnglishMonth);
    }

    /**
     * Get/set the day of year.
     *
     * @param int|null $value new value for day of year if using as setter.
     *
     * @return static|CarbonInterface|int
     */
    public function dayOfYear($value = null)
    {
        $dayOfYear = $this->dayOfYear;

        return is_null($value) ? $dayOfYear : $this->addDays($value - $dayOfYear);
    }

    /**
     * Get/set the weekday from 0 (Sunday) to 6 (Saturday).
     *
     * @param int|null $value new value for weekday if using as setter.
     *
     * @return static|CarbonInterface|int
     */
    public function weekday($value = null)
    {
        $dayOfWeek = ($this->dayOfWeek + 7 - intval($this->getTranslationMessage('first_day_of_week') ?? 0)) % 7;

        return is_null($value) ? $dayOfWeek : $this->addDays($value - $dayOfWeek);
    }

    /**
     * Get/set the ISO weekday from 1 (Monday) to 7 (Sunday).
     *
     * @param int|null $value new value for weekday if using as setter.
     *
     * @return static|CarbonInterface|int
     */
    public function isoWeekday($value = null)
    {
        $dayOfWeekIso = $this->dayOfWeekIso;

        return is_null($value) ? $dayOfWeekIso : $this->addDays($value - $dayOfWeekIso);
    }

    /**
     * Set any unit to a new value without overflowing current other unit given.
     *
     * @param string $valueUnit    unit name to modify
     * @param int    $value        new value for the input unit
     * @param string $overflowUnit unit name to not overflow
     *
     * @return static|CarbonInterface
     */
    public function setUnitNoOverflow($valueUnit, $value, $overflowUnit)
    {
        try {
            $original = $this->copy();
            /** @var CarbonInterface $date */
            $date = $this->$valueUnit($value);
            $end = $original->copy()->endOf($overflowUnit);
            $start = $original->copy()->startOf($overflowUnit);
            if ($date < $start) {
                $date = $date->setDateTimeFrom($start);
            } elseif ($date > $end) {
                $date = $date->setDateTimeFrom($end);
            }

            return $date;
        } catch (BadMethodCallException | ReflectionException $exception) {
            throw new InvalidArgumentException("Unknown unit '$valueUnit'", 0, $exception);
        }
    }

    /**
     * Add any unit to a new value without overflowing current other unit given.
     *
     * @param string $valueUnit    unit name to modify
     * @param int    $value        amount to add to the input unit
     * @param string $overflowUnit unit name to not overflow
     *
     * @return static|CarbonInterface
     */
    public function addUnitNoOverflow($valueUnit, $value, $overflowUnit)
    {
        return $this->setUnitNoOverflow($valueUnit, $this->$valueUnit + $value, $overflowUnit);
    }

    /**
     * Subtract any unit to a new value without overflowing current other unit given.
     *
     * @param string $valueUnit    unit name to modify
     * @param int    $value        amount to subtract to the input unit
     * @param string $overflowUnit unit name to not overflow
     *
     * @return static|CarbonInterface
     */
    public function subUnitNoOverflow($valueUnit, $value, $overflowUnit)
    {
        return $this->setUnitNoOverflow($valueUnit, $this->$valueUnit - $value, $overflowUnit);
    }

    /**
     * Returns the minutes offset to UTC if no arguments passed, else set the timezone with given minutes shift passed.
     *
     * @param int|null $offset
     *
     * @return int|static|CarbonInterface
     */
    public function utcOffset(int $offset = null)
    {
        if (func_num_args() < 1) {
            return $this->offsetMinutes;
        }

        return $this->setTimezone(static::safeCreateDateTimeZone($offset / static::MINUTES_PER_HOUR));
    }

    /**
     * Set the date and time all together.
     *
     * @param int $year
     * @param int $month
     * @param int $day
     * @param int $hour
     * @param int $minute
     * @param int $second
     * @param int $microseconds
     *
     * @return static|CarbonInterface
     */
    public function setDateTime($year, $month, $day, $hour, $minute, $second = 0, $microseconds = 0)
    {
        return $this->setDate($year, $month, $day)->setTime($hour, $minute, $second, $microseconds);
    }

    /**
     * Set the time by time string.
     *
     * @param string $time
     *
     * @return static|CarbonInterface
     */
    public function setTimeFromTimeString($time)
    {
        if (strpos($time, ':') === false) {
            $time .= ':0';
        }

        return $this->modify($time);
    }

    /**
     * @alias setTimezone
     *
     * @param \DateTimeZone|string $value
     *
     * @return static|CarbonInterface
     */
    public function timezone($value)
    {
        return $this->setTimezone($value);
    }

    /**
     * Set the timezone or returns the timezone name if no arguments passed.
     *
     * @param \DateTimeZone|string $value
     *
     * @return CarbonInterface|string
     */
    public function tz($value = null)
    {
        if (func_num_args() < 1) {
            return $this->tzName;
        }

        return $this->setTimezone($value);
    }

    /**
     * Set the instance's timezone from a string or object.
     *
     * @param \DateTimeZone|string $value
     *
     * @return static|CarbonInterface
     */
    public function setTimezone($value)
    {
        /** @var static $date */
        $date = parent::setTimezone(static::safeCreateDateTimeZone($value));
        // https://bugs.php.net/bug.php?id=72338
        // just workaround on this bug
        $date->getTimestamp();

        return $date;
    }

    /**
     * Set the instance's timezone from a string or object and add/subtract the offset difference.
     *
     * @param \DateTimeZone|string $value
     *
     * @return static|CarbonInterface
     */
    public function shiftTimezone($value)
    {
        $offset = $this->offset;
        $date = $this->setTimezone($value);

        return $date->addRealMicroseconds(($offset - $date->offset) * static::MICROSECONDS_PER_SECOND);
    }

    /**
     * Set the instance's timezone to UTC.
     *
     * @return static|CarbonInterface
     */
    public function utc()
    {
        return $this->setTimezone('UTC');
    }

    /**
     * Set the year, month, and date for this instance to that of the passed instance.
     *
     * @param \Carbon\Carbon|\DateTimeInterface $date now if null
     *
     * @return static
     */
    public function setDateFrom($date = null)
    {
        $date = $this->resolveCarbon($date);

        return $this->setDate($date->year, $date->month, $date->day);
    }

    /**
     * Set the hour, minute, second and microseconds for this instance to that of the passed instance.
     *
     * @param \Carbon\Carbon|\DateTimeInterface $date now if null
     *
     * @return static
     */
    public function setTimeFrom($date = null)
    {
        $date = $this->resolveCarbon($date);

        return $this->setTime($date->hour, $date->minute, $date->second, $date->microsecond);
    }

    /**
     * Set the date and time for this instance to that of the passed instance.
     *
     * @param \Carbon\Carbon|\DateTimeInterface $date
     *
     * @return static
     */
    public function setDateTimeFrom($date = null)
    {
        $date = $this->resolveCarbon($date);

        return $this->modify($date->rawFormat('Y-m-d H:i:s.u'));
    }

    /**
     * Get the days of the week
     *
     * @return array
     */
    public static function getDays()
    {
        return static::$days;
    }

    ///////////////////////////////////////////////////////////////////
    /////////////////////// WEEK SPECIAL DAYS /////////////////////////
    ///////////////////////////////////////////////////////////////////

    /**
     * Get the first day of week
     *
     * @return int
     */
    public static function getWeekStartsAt()
    {
        return static::$weekStartsAt;
    }

    /**
     * @deprecated To avoid conflict between different third-party libraries, static setters should not be used.
     *             Use $weekEndsAt optional parameter instead when using endOfWeek method. You can also use the
     *             'first_day_of_week' locale setting to change the start of week according to current locale
     *             selected and implicitly the end of week.
     *
     * Set the first day of week
     *
     * @param int $day week start day
     *
     * @return void
     */
    public static function setWeekStartsAt($day)
    {
        static::$weekStartsAt = max(0, (7 + $day) % 7);
    }

    /**
     * Get the last day of week
     *
     * @return int
     */
    public static function getWeekEndsAt()
    {
        return static::$weekEndsAt;
    }

    /**
     * @deprecated To avoid conflict between different third-party libraries, static setters should not be used.
     *             Use $weekStartsAt optional parameter instead when using startOfWeek, floorWeek, ceilWeek
     *             or roundWeek method. You can also use the 'first_day_of_week' locale setting to change the
     *             start of week according to current locale selected and implicitly the end of week.
     *
     * Set the last day of week
     *
     * @param int $day
     *
     * @return void
     */
    public static function setWeekEndsAt($day)
    {
        static::$weekEndsAt = max(0, (7 + $day) % 7);
    }

    /**
     * Get weekend days
     *
     * @return array
     */
    public static function getWeekendDays()
    {
        return static::$weekendDays;
    }

    /**
     * @deprecated To avoid conflict between different third-party libraries, static setters should not be used.
     *             You should rather consider week-end is always saturday and sunday, and if you have some custom
     *             week-end days to handle, give to those days an other name and create a macro for them:
     *
     *             ```
     *             Carbon::macro('isDayOff', function ($date) {
     *                 return $date->isSunday() || $date->isMonday();
     *             });
     *             Carbon::macro('isNotDayOff', function ($date) {
     *                 return !$date->isDayOff();
     *             });
     *             if ($someDate->isDayOff()) ...
     *             if ($someDate->isNotDayOff()) ...
     *             // Add 5 not-off days
     *             $count = 5;
     *             while ($someDate->isDayOff() || ($count-- > 0)) {
     *                 $someDate->addDay();
     *             }
     *             ```
     *
     * Set weekend days
     *
     * @param array $days
     *
     * @return void
     */
    public static function setWeekendDays($days)
    {
        static::$weekendDays = $days;
    }

    /**
     * Determine if a time string will produce a relative date.
     *
     * @param string $time
     *
     * @return bool true if time match a relative date, false if absolute or invalid time string
     */
    public static function hasRelativeKeywords($time)
    {
        if (strtotime($time) === false) {
            return false;
        }

        $date1 = new DateTime('2000-01-01T00:00:00Z');
        $date1->modify($time);
        $date2 = new DateTime('2001-12-25T00:00:00Z');
        $date2->modify($time);

        return $date1 != $date2;
    }

    ///////////////////////////////////////////////////////////////////
    /////////////////////// STRING FORMATTING /////////////////////////
    ///////////////////////////////////////////////////////////////////

    /**
     * @deprecated To avoid conflict between different third-party libraries, static setters should not be used.
     *             You should rather use UTF-8 language packages on every machine.
     *
     * Set if UTF8 will be used for localized date/time.
     *
     * @param bool $utf8
     */
    public static function setUtf8($utf8)
    {
        static::$utf8 = $utf8;
    }

    /**
     * Format the instance with the current locale.  You can set the current
     * locale using setlocale() http://php.net/setlocale.
     *
     * @param string $format
     *
     * @return string
     */
    public function formatLocalized($format)
    {
        // Check for Windows to find and replace the %e modifier correctly.
        if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') {
            $format = preg_replace('#(?<!%)((?:%%)*)%e#', '\1%#d', $format); // @codeCoverageIgnore
        }

        $formatted = strftime($format, strtotime($this->toDateTimeString()));

        return static::$utf8 ? utf8_encode($formatted) : $formatted;
    }

    /**
     * Returns list of locale formats for ISO formatting.
     *
     * @param string|null $locale current locale used if null
     *
     * @return array
     */
    public function getIsoFormats($locale = null)
    {
        return [
            'LT' => $this->getTranslationMessage('formats.LT', $locale, 'h:mm A'),
            'LTS' => $this->getTranslationMessage('formats.LTS', $locale, 'h:mm:ss A'),
            'L' => $this->getTranslationMessage('formats.L', $locale, 'MM/DD/YYYY'),
            'LL' => $this->getTranslationMessage('formats.LL', $locale, 'MMMM D, YYYY'),
            'LLL' => $this->getTranslationMessage('formats.LLL', $locale, 'MMMM D, YYYY h:mm A'),
            'LLLL' => $this->getTranslationMessage('formats.LLLL', $locale, 'dddd, MMMM D, YYYY h:mm A'),
        ];
    }

    /**
     * Returns list of calendar formats for ISO formatting.
     *
     * @param string|null $locale current locale used if null
     *
     * @return array
     */
    public function getCalendarFormats($locale = null)
    {
        return [
            'sameDay' => $this->getTranslationMessage('calendar.sameDay', $locale, '[Today at] LT'),
            'nextDay' => $this->getTranslationMessage('calendar.nextDay', $locale, '[Tomorrow at] LT'),
            'nextWeek' => $this->getTranslationMessage('calendar.nextWeek', $locale, 'dddd [at] LT'),
            'lastDay' => $this->getTranslationMessage('calendar.lastDay', $locale, '[Yesterday at] LT'),
            'lastWeek' => $this->getTranslationMessage('calendar.lastWeek', $locale, '[Last] dddd [at] LT'),
            'sameElse' => $this->getTranslationMessage('calendar.sameElse', $locale, 'L'),
        ];
    }

    /**
     * Returns list of locale units for ISO formatting.
     *
     * @return array
     */
    public static function getIsoUnits()
    {
        static $units = null;

        if ($units === null) {
            $units = [
                'OD' => ['getAltNumber', ['day']],
                'OM' => ['getAltNumber', ['month']],
                'OY' => ['getAltNumber', ['year']],
                'OH' => ['getAltNumber', ['hour']],
                'Oh' => ['getAltNumber', ['h']],
                'Om' => ['getAltNumber', ['minute']],
                'Os' => ['getAltNumber', ['second']],
                'D' => 'day',
                'DD' => ['rawFormat', ['d']],
                'Do' => ['ordinal', ['day', 'D']],
                'd' => 'dayOfWeek',
                'dd' => function (CarbonInterface $date, $originalFormat = null) {
                    return $date->getTranslatedMinDayName($originalFormat);
                },
                'ddd' => function (CarbonInterface $date, $originalFormat = null) {
                    return $date->getTranslatedShortDayName($originalFormat);
                },
                'dddd' => function (CarbonInterface $date, $originalFormat = null) {
                    return $date->getTranslatedDayName($originalFormat);
                },
                'DDD' => 'dayOfYear',
                'DDDD' => ['getPaddedUnit', ['dayOfYear', 3]],
                'DDDo' => ['ordinal', ['dayOfYear', 'DDD']],
                'e' => ['weekday', []],
                'E' => 'dayOfWeekIso',
                'H' => ['rawFormat', ['G']],
                'HH' => ['rawFormat', ['H']],
                'h' => ['rawFormat', ['g']],
                'hh' => ['rawFormat', ['h']],
                'k' => 'noZeroHour',
                'kk' => ['getPaddedUnit', ['noZeroHour']],
                'hmm' => ['rawFormat', ['gi']],
                'hmmss' => ['rawFormat', ['gis']],
                'Hmm' => ['rawFormat', ['Gi']],
                'Hmmss' => ['rawFormat', ['Gis']],
                'm' => 'minute',
                'mm' => ['rawFormat', ['i']],
                'a' => 'meridiem',
                'A' => 'upperMeridiem',
                's' => 'second',
                'ss' => ['getPaddedUnit', ['second']],
                'S' => function (CarbonInterface $date) {
                    return strval(floor($date->micro / 100000));
                },
                'SS' => function (CarbonInterface $date) {
                    return str_pad(floor($date->micro / 10000), 2, '0', STR_PAD_LEFT);
                },
                'SSS' => function (CarbonInterface $date) {
                    return str_pad(floor($date->micro / 1000), 3, '0', STR_PAD_LEFT);
                },
                'SSSS' => function (CarbonInterface $date) {
                    return str_pad(floor($date->micro / 100), 4, '0', STR_PAD_LEFT);
                },
                'SSSSS' => function (CarbonInterface $date) {
                    return str_pad(floor($date->micro / 10), 5, '0', STR_PAD_LEFT);
                },
                'SSSSSS' => ['getPaddedUnit', ['micro', 6]],
                'SSSSSSS' => function (CarbonInterface $date) {
                    return str_pad(floor($date->micro * 10), 7, '0', STR_PAD_LEFT);
                },
                'SSSSSSSS' => function (CarbonInterface $date) {
                    return str_pad(floor($date->micro * 100), 8, '0', STR_PAD_LEFT);
                },
                'SSSSSSSSS' => function (CarbonInterface $date) {
                    return str_pad(floor($date->micro * 1000), 9, '0', STR_PAD_LEFT);
                },
                'M' => 'month',
                'MM' => ['rawFormat', ['m']],
                'MMM' => function (CarbonInterface $date, $originalFormat = null) {
                    $month = $date->getTranslatedShortMonthName($originalFormat);
                    $suffix = $date->getTranslationMessage('mmm_suffix');
                    if ($suffix && $month !== $date->monthName) {
                        $month .= $suffix;
                    }

                    return $month;
                },
                'MMMM' => function (CarbonInterface $date, $originalFormat = null) {
                    return $date->getTranslatedMonthName($originalFormat);
                },
                'Mo' => ['ordinal', ['month', 'M']],
                'Q' => 'quarter',
                'Qo' => ['ordinal', ['quarter', 'M']],
                'G' => 'isoWeekYear',
                'GG' => ['getPaddedUnit', ['isoWeekYear']],
                'GGG' => ['getPaddedUnit', ['isoWeekYear', 3]],
                'GGGG' => ['getPaddedUnit', ['isoWeekYear', 4]],
                'GGGGG' => ['getPaddedUnit', ['isoWeekYear', 5]],
                'g' => 'weekYear',
                'gg' => ['getPaddedUnit', ['weekYear']],
                'ggg' => ['getPaddedUnit', ['weekYear', 3]],
                'gggg' => ['getPaddedUnit', ['weekYear', 4]],
                'ggggg' => ['getPaddedUnit', ['weekYear', 5]],
                'W' => 'isoWeek',
                'WW' => ['getPaddedUnit', ['isoWeek']],
                'Wo' => ['ordinal', ['isoWeek', 'W']],
                'w' => 'week',
                'ww' => ['getPaddedUnit', ['week']],
                'wo' => ['ordinal', ['week', 'w']],
                'x' => ['valueOf', []],
                'X' => 'timestamp',
                'Y' => 'year',
                'YY' => ['rawFormat', ['y']],
                'YYYY' => ['getPaddedUnit', ['year', 4]],
                'YYYYY' => ['getPaddedUnit', ['year', 5]],
                'YYYYYY' => function (CarbonInterface $date) {
                    return ($date->year < 0 ? '' : '+').$date->getPaddedUnit('year', 6);
                },
                'z' => 'tzAbbrName',
                'zz' => 'tzName',
                'Z' => ['getOffsetString', []],
                'ZZ' => ['getOffsetString', ['']],
            ];
        }

        return $units;
    }

    /**
     * Returns a unit of the instance padded with 0 by default or any other string if specified.
     *
     * @param string $unit      Carbon unit name
     * @param int    $length    Length of the output (2 by default)
     * @param string $padString String to use for padding ("0" by default)
     * @param int    $padType   Side(s) to pad (STR_PAD_LEFT by default)
     *
     * @return string
     */
    public function getPaddedUnit($unit, $length = 2, $padString = '0', $padType = STR_PAD_LEFT)
    {
        return ($this->$unit < 0 ? '-' : '').str_pad(abs($this->$unit), $length, $padString, $padType);
    }

    /**
     * Return a property with its ordinal.
     *
     * @param string      $key
     * @param string|null $period
     *
     * @return string
     */
    public function ordinal(string $key, string $period = null): string
    {
        $number = $this->$key;
        $result = $this->translate('ordinal', [
            ':number' => $number,
            ':period' => $period,
        ]);

        return strval($result === 'ordinal' ? $number : $result);
    }

    /**
     * Return the meridiem of the current time in the current locale.
     *
     * @param bool $isLower if true, returns lowercase variant if available in the current locale.
     *
     * @return string
     */
    public function meridiem(bool $isLower = false): string
    {
        $hour = $this->hour;
        $index = $hour < 12 ? 0 : 1;

        if ($isLower) {
            $key = 'meridiem.'.($index + 2);
            $result = $this->translate($key);

            if ($result !== $key) {
                return $result;
            }
        }

        $key = "meridiem.$index";
        $result = $this->translate($key);
        if ($result === $key) {
            $result = $this->translate('meridiem', [
                ':hour' => $this->hour,
                ':minute' => $this->minute,
                ':isLower' => $isLower,
            ]);

            if ($result === 'meridiem') {
                return $isLower ? $this->latinMeridiem : $this->latinUpperMeridiem;
            }
        } elseif ($isLower) {
            $result = mb_strtolower($result);
        }

        return $result;
    }

    /**
     * Returns the alternative number if available in the current locale.
     *
     * @param string $key date property
     *
     * @return string
     */
    public function getAltNumber(string $key): string
    {
        $number = strlen($key) > 1 ? $this->$key : $this->rawFormat('h');
        $translateKey = "alt_numbers.$number";
        $symbol = $this->translate($translateKey);

        if ($symbol !== $translateKey) {
            return $symbol;
        }

        if ($number > 99 && $this->translate('alt_numbers.99') !== 'alt_numbers.99') {
            $start = '';
            foreach ([10000, 1000, 100] as $exp) {
                $key = "alt_numbers_pow.$exp";
                if ($number >= $exp && $number < $exp * 10 && ($pow = $this->translate($key)) !== $key) {
                    $unit = floor($number / $exp);
                    $number -= $unit * $exp;
                    $start .= ($unit > 1 ? $this->translate("alt_numbers.$unit") : '').$pow;
                }
            }
            $result = '';
            while ($number) {
                $chunk = $number % 100;
                $result = $this->translate("alt_numbers.$chunk").$result;
                $number = floor($number / 100);
            }

            return "$start$result";
        }

        if ($number > 9 && $this->translate('alt_numbers.9') !== 'alt_numbers.9') {
            $result = '';
            while ($number) {
                $chunk = $number % 10;
                $result = $this->translate("alt_numbers.$chunk").$result;
                $number = floor($number / 10);
            }

            return $result;
        }

        return $number;
    }

    /**
     * Format in the current language using ISO replacement patterns.
     *
     * @param string      $format
     * @param string|null $originalFormat provide context if a chunk has been passed alone
     *
     * @return string
     */
    public function isoFormat(string $format, string $originalFormat = null): string
    {
        $result = '';
        $length = mb_strlen($format);
        $originalFormat = $originalFormat ?: $format;
        $inEscaped = false;
        $formats = null;
        $units = null;

        for ($i = 0; $i < $length; $i++) {
            $char = mb_substr($format, $i, 1);

            if ($char === '\\') {
                $result .= mb_substr($format, ++$i, 1);

                continue;
            }

            if ($char === '[' && !$inEscaped) {
                $inEscaped = true;

                continue;
            }

            if ($char === ']' && $inEscaped) {
                $inEscaped = false;

                continue;
            }

            if ($inEscaped) {
                $result .= $char;

                continue;
            }

            $input = mb_substr($format, $i);

            if (preg_match('/^(LTS|LT|[Ll]{1,4})/', $input, $match)) {
                if ($formats === null) {
                    $formats = $this->getIsoFormats();
                }

                $code = $match[0];
                $sequence = $formats[$code] ?? preg_replace_callback(
                    '/MMMM|MM|DD|dddd/',
                    function ($code) {
                        return mb_substr($code[0], 1);
                    },
                    $formats[strtoupper($code)] ?? ''
                );
                $rest = mb_substr($format, $i + mb_strlen($code));
                $format = mb_substr($format, 0, $i).$sequence.$rest;
                $length = mb_strlen($format);
                $input = $sequence.$rest;
            }

            if (preg_match('/^'.CarbonInterface::ISO_FORMAT_REGEXP.'/', $input, $match)) {
                $code = $match[0];

                if ($units === null) {
                    $units = static::getIsoUnits();
                }

                $sequence = $units[$code] ?? '';

                if ($sequence instanceof Closure) {
                    $sequence = $sequence($this, $originalFormat);
                } elseif (is_array($sequence)) {
                    try {
                        $sequence = $this->{$sequence[0]}(...$sequence[1]);
                    } catch (ReflectionException | InvalidArgumentException | BadMethodCallException $e) {
                        $sequence = '';
                    }
                } elseif (is_string($sequence)) {
                    $sequence = $this->$sequence ?? $code;
                }

                $format = mb_substr($format, 0, $i).$sequence.mb_substr($format, $i + mb_strlen($code));
                $i += mb_strlen($sequence) - 1;
                $length = mb_strlen($format);
                $char = $sequence;
            }

            $result .= $char;
        }

        return $result;
    }

    /**
     * List of replacements from date() format to isoFormat().
     *
     * @return array
     */
    public static function getFormatsToIsoReplacements()
    {
        static $replacements = null;

        if ($replacements === null) {
            $replacements = [
                'd' => true,
                'D' => 'ddd',
                'j' => true,
                'l' => 'dddd',
                'N' => true,
                'S' => function ($date) {
                    $day = $date->rawFormat('j');

                    return str_replace("$day", '', $date->isoFormat('Do'));
                },
                'w' => true,
                'z' => true,
                'W' => true,
                'F' => 'MMMM',
                'm' => true,
                'M' => 'MMM',
                'n' => true,
                't' => true,
                'L' => true,
                'o' => true,
                'Y' => true,
                'y' => true,
                'a' => 'a',
                'A' => 'A',
                'B' => true,
                'g' => true,
                'G' => true,
                'h' => true,
                'H' => true,
                'i' => true,
                's' => true,
                'u' => true,
                'v' => true,
                'E' => true,
                'I' => true,
                'O' => true,
                'P' => true,
                'Z' => true,
                'c' => true,
                'r' => true,
                'U' => true,
            ];
        }

        return $replacements;
    }

    /**
     * Format as ->format() do (using date replacements patterns from http://php.net/manual/fr/function.date.php)
     * but translate words whenever possible (months, day names, etc.) using the current locale.
     *
     * @param string $format
     *
     * @return string
     */
    public function translatedFormat(string $format): string
    {
        $replacements = static::getFormatsToIsoReplacements();
        $context = '';
        $isoFormat = '';
        $length = mb_strlen($format);

        for ($i = 0; $i < $length; $i++) {
            $char = mb_substr($format, $i, 1);

            if ($char === '\\') {
                $replacement = mb_substr($format, $i, 2);
                $isoFormat .= $replacement;
                $i++;

                continue;
            }

            if (!isset($replacements[$char])) {
                $replacement = preg_match('/^[A-Za-z]$/', $char) ? "\\$char" : $char;
                $isoFormat .= $replacement;
                $context .= $replacement;

                continue;
            }

            $replacement = $replacements[$char];

            if ($replacement === true) {
                static $contextReplacements = null;

                if ($contextReplacements === null) {
                    $contextReplacements = [
                        'm' => 'MM',
                        'd' => 'DD',
                        't' => 'D',
                        'j' => 'D',
                        'N' => 'e',
                        'w' => 'e',
                        'n' => 'M',
                        'o' => 'YYYY',
                        'Y' => 'YYYY',
                        'y' => 'YY',
                        'g' => 'h',
                        'G' => 'H',
                        'h' => 'hh',
                        'H' => 'HH',
                        'i' => 'mm',
                        's' => 'ss',
                    ];
                }

                $isoFormat .= '['.$this->rawFormat($char).']';
                $context .= $contextReplacements[$char] ?? ' ';

                continue;
            }

            if ($replacement instanceof Closure) {
                $replacement = '['.$replacement($this).']';
                $isoFormat .= $replacement;
                $context .= $replacement;

                continue;
            }

            $isoFormat .= $replacement;
            $context .= $replacement;
        }

        return $this->isoFormat($isoFormat, $context);
    }

    /**
     * Returns the offset hour and minute formatted with +/- and a given separator (":" by default).
     * For example, if the time zone is 9 hours 30 minutes, you'll get "+09:30", with "@@" as first
     * argument, "+09@@30", with "" as first argument, "+0930". Negative offset will return something
     * like "-12:00".
     *
     * @param string $separator string to place between hours and minutes (":" by default)
     *
     * @return string
     */
    public function getOffsetString($separator = ':')
    {
        $second = $this->getOffset();
        $symbol = $second < 0 ? '-' : '+';
        $minute = abs($second) / static::SECONDS_PER_MINUTE;
        $hour = str_pad(floor($minute / static::MINUTES_PER_HOUR), 2, '0', STR_PAD_LEFT);
        $minute = str_pad($minute % static::MINUTES_PER_HOUR, 2, '0', STR_PAD_LEFT);

        return "$symbol$hour$separator$minute";
    }

    protected static function executeStaticCallable($macro, ...$parameters)
    {
        if ($macro instanceof Closure) {
            return call_user_func_array(Closure::bind($macro, null, get_called_class()), $parameters);
        }

        return call_user_func_array($macro, $parameters);
    }

    /**
     * Dynamically handle calls to the class.
     *
     * @param string $method     magic method name called
     * @param array  $parameters parameters list
     *
     * @throws \BadMethodCallException
     *
     * @return mixed
     */
    public static function __callStatic($method, $parameters)
    {
        if (!static::hasMacro($method)) {
            foreach (static::getGenericMacros() as $callback) {
                try {
                    return static::executeStaticCallable($callback, $method, ...$parameters);
                } catch (BadMethodCallException $exception) {
                    continue;
                }
            }
            if (static::isStrictModeEnabled()) {
                throw new BadMethodCallException(sprintf(
                    'Method %s::%s does not exist.', static::class, $method
                ));
            }

            return null;
        }

        return static::executeStaticCallable(static::$globalMacros[$method], ...$parameters);
    }

    /**
     * Set specified unit to new given value.
     *
     * @param string $unit  year, month, day, hour, minute, second or microsecond
     * @param int    $value new value for given unit
     *
     * @return static
     */
    public function setUnit($unit, $value = null)
    {
        $unit = static::singularUnit($unit);
        $dateUnits = ['year', 'month', 'day'];
        if (in_array($unit, $dateUnits)) {
            return $this->setDate(...array_map(function ($name) use ($unit, $value) {
                return $name === $unit ? $value : $this->$name;
            }, $dateUnits));
        }

        $units = ['hour', 'minute', 'second', 'micro'];
        if ($unit === 'millisecond' || $unit === 'milli') {
            $value *= 1000;
            $unit = 'micro';
        } elseif ($unit === 'microsecond') {
            $unit = 'micro';
        }

        return $this->setTime(...array_map(function ($name) use ($unit, $value) {
            return $name === $unit ? $value : $this->$name;
        }, $units));
    }

    /**
     * Returns standardized singular of a given singular/plural unit name (in English).
     *
     * @param string $unit
     *
     * @return string
     */
    public static function singularUnit(string $unit): string
    {
        $unit = rtrim(strtolower($unit), 's');

        if ($unit === 'centurie') {
            return 'century';
        }

        if ($unit === 'millennia') {
            return 'millennium';
        }

        return $unit;
    }

    /**
     * Returns standardized plural of a given singular/plural unit name (in English).
     *
     * @param string $unit
     *
     * @return string
     */
    public static function pluralUnit(string $unit): string
    {
        $unit = rtrim(strtolower($unit), 's');

        if ($unit === 'century') {
            return 'centuries';
        }

        if ($unit === 'millennium' || $unit === 'millennia') {
            return 'millennia';
        }

        return "${unit}s";
    }

    protected function executeCallable($macro, ...$parameters)
    {
        if ($macro instanceof Closure) {
            return call_user_func_array($macro->bindTo($this, static::class), $parameters);
        }

        return call_user_func_array($macro, $parameters);
    }

    protected static function getGenericMacros()
    {
        foreach (static::$globalGenericMacros as $list) {
            foreach ($list as $macro) {
                yield $macro;
            }
        }
    }

    /**
     * Dynamically handle calls to the class.
     *
     * @param string $method     magic method name called
     * @param array  $parameters parameters list
     *
     * @throws \BadMethodCallException|\ReflectionException
     *
     * @return mixed
     */
    public function __call($method, $parameters)
    {
        $diffSizes = [
            // @mode diffForHumans
            'short' => true,
            // @mode diffForHumans
            'long' => false,
        ];
        $diffSyntaxModes = [
            // @call diffForHumans
            'Absolute' => CarbonInterface::DIFF_ABSOLUTE,
            // @call diffForHumans
            'Relative' => CarbonInterface::DIFF_RELATIVE_AUTO,
            // @call diffForHumans
            'RelativeToNow' => CarbonInterface::DIFF_RELATIVE_TO_NOW,
            // @call diffForHumans
            'RelativeToOther' => CarbonInterface::DIFF_RELATIVE_TO_OTHER,
        ];
        $sizePattern = implode('|', array_keys($diffSizes));
        $syntaxPattern = implode('|', array_keys($diffSyntaxModes));
        if (preg_match("/^(?<size>$sizePattern)(?<syntax>$syntaxPattern)DiffForHumans$/", $method, $match)) {
            $dates = array_filter($parameters, function ($parameter) {
                return $parameter instanceof DateTimeInterface;
            });
            $other = null;
            if (count($dates)) {
                $key = key($dates);
                $other = current($dates);
                array_splice($parameters, $key, 1);
            }

            return $this->diffForHumans($other, $diffSyntaxModes[$match['syntax']], $diffSizes[$match['size']], ...$parameters);
        }

        $action = substr($method, 0, 4);
        if ($action !== 'ceil') {
            $action = substr($method, 0, 5);
        }
        if (in_array($action, ['round', 'floor', 'ceil'])) {
            return $this->{$action.'Unit'}(substr($method, strlen($action)), ...$parameters);
        }

        $unit = rtrim($method, 's');
        if (substr($unit, 0, 2) === 'is') {
            $word = substr($unit, 2);
            if (in_array($word, static::$days)) {
                return $this->isDayOfWeek($word);
            }
            switch ($word) {
                // @call is Check if the current instance has UTC timezone. (Both isUtc and isUTC cases are valid.)
                case 'Utc':
                case 'UTC':
                    return $this->utc;
                // @call is Check if the current instance has non-UTC timezone.
                case 'Local':
                    return $this->local;
                // @call is Check if the current instance is a valid date.
                case 'Valid':
                    return $this->year !== 0;
                // @call is Check if the current instance is in a daylight saving time.
                case 'DST':
                    return $this->dst;
            }
        }

        $action = substr($unit, 0, 3);
        $overflow = null;
        if ($action === 'set') {
            $unit = strtolower(substr($unit, 3));
        }

        if (in_array($unit, static::$units)) {
            return $this->setUnit($unit, ...$parameters);
        }

        if ($action === 'add' || $action === 'sub') {
            $unit = substr($unit, 3);
            if (substr($unit, 0, 4) === 'Real') {
                $unit = static::singularUnit(substr($unit, 4));

                return $this->{"${action}RealUnit"}($unit, ...$parameters);
            }

            if (preg_match('/^(Month|Quarter|Year|Decade|Century|Centurie|Millennium|Millennia)s?(No|With|Without|WithNo)Overflow$/', $unit, $match)) {
                $unit = $match[1];
                $overflow = $match[2] === 'With';
            }
            $unit = static::singularUnit($unit);
        }

        if (static::isModifiableUnit($unit)) {
            return $this->{"${action}Unit"}($unit, $parameters[0] ?? 1, $overflow);
        }

        $sixFirstLetters = substr($unit, 0, 6);
        $factor = -1;

        if ($sixFirstLetters === 'isLast') {
            $sixFirstLetters = 'isNext';
            $factor = 1;
        }

        if ($sixFirstLetters === 'isNext') {
            $lowerUnit = strtolower(substr($unit, 6));

            if (static::isModifiableUnit($lowerUnit)) {
                return $this->copy()->addUnit($lowerUnit, $factor, false)->isSameUnit($lowerUnit, ...$parameters);
            }
        }

        if ($sixFirstLetters === 'isSame') {
            try {
                return $this->isSameUnit(strtolower(substr($unit, 6)), ...$parameters);
            } catch (InvalidArgumentException $exception) {
                // Try next
            }
        }

        if (substr($unit, 0, 9) === 'isCurrent') {
            try {
                return $this->isCurrentUnit(strtolower(substr($unit, 9)));
            } catch (InvalidArgumentException | BadMethodCallException $exception) {
                // Try macros
            }
        }

        if (!static::hasMacro($method)) {
            foreach ([$this->localGenericMacros ?: [], static::getGenericMacros()] as $list) {
                foreach ($list as $callback) {
                    try {
                        return $this->executeCallable($callback, $method, ...$parameters);
                    } catch (BadMethodCallException $exception) {
                        continue;
                    }
                }
            }
            if ($this->localStrictModeEnabled ?? static::isStrictModeEnabled()) {
                throw new BadMethodCallException("Method $method does not exist.");
            }

            return null;
        }

        return $this->executeCallable(($this->localMacros ?? [])[$method] ?? static::$globalMacros[$method], ...$parameters);
    }
}
