diff --git a/src/Carbon/CarbonImmutable.php b/src/Carbon/CarbonImmutable.php new file mode 100644 index 0000000..29edbb8 --- /dev/null +++ b/src/Carbon/CarbonImmutable.php @@ -0,0 +1,892 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Carbon; + +use Carbon\Traits\Date; +use DateTimeImmutable; +use DateTimeInterface; + +/** + * A simple API extension for DateTimeImmutable. + * + * + * + * @property string $localeDayOfWeek the day of week in current locale + * @property string $shortLocaleDayOfWeek the abbreviated day of week in current locale + * @property string $localeMonth the month in current locale + * @property string $shortLocaleMonth the abbreviated month in current locale + * @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 $dayOfWeekIso 1 (for Monday) through 7 (for Sunday) + * @property int|float|string $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 month in English + * @property string $shortEnglishMonth the abbreviated month in English + * @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 $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 int $centuryOfMillennium The value of the century starting from the beginning of the current millennium + * @property int $dayOfCentury The value of the day starting from the beginning of the current century + * @property int $dayOfDecade The value of the day starting from the beginning of the current decade + * @property int $dayOfMillennium The value of the day starting from the beginning of the current millennium + * @property int $dayOfMonth The value of the day starting from the beginning of the current month + * @property int $dayOfQuarter The value of the day starting from the beginning of the current quarter + * @property int $dayOfWeek 0 (for Sunday) through 6 (for Saturday) + * @property int $dayOfYear 1 through 366 + * @property int $decadeOfCentury The value of the decade starting from the beginning of the current century + * @property int $decadeOfMillennium The value of the decade starting from the beginning of the current millennium + * @property int $hourOfCentury The value of the hour starting from the beginning of the current century + * @property int $hourOfDay The value of the hour starting from the beginning of the current day + * @property int $hourOfDecade The value of the hour starting from the beginning of the current decade + * @property int $hourOfMillennium The value of the hour starting from the beginning of the current millennium + * @property int $hourOfMonth The value of the hour starting from the beginning of the current month + * @property int $hourOfQuarter The value of the hour starting from the beginning of the current quarter + * @property int $hourOfWeek The value of the hour starting from the beginning of the current week + * @property int $hourOfYear The value of the hour starting from the beginning of the current year + * @property int $microsecondOfCentury The value of the microsecond starting from the beginning of the current century + * @property int $microsecondOfDay The value of the microsecond starting from the beginning of the current day + * @property int $microsecondOfDecade The value of the microsecond starting from the beginning of the current decade + * @property int $microsecondOfHour The value of the microsecond starting from the beginning of the current hour + * @property int $microsecondOfMillennium The value of the microsecond starting from the beginning of the current millennium + * @property int $microsecondOfMillisecond The value of the microsecond starting from the beginning of the current millisecond + * @property int $microsecondOfMinute The value of the microsecond starting from the beginning of the current minute + * @property int $microsecondOfMonth The value of the microsecond starting from the beginning of the current month + * @property int $microsecondOfQuarter The value of the microsecond starting from the beginning of the current quarter + * @property int $microsecondOfSecond The value of the microsecond starting from the beginning of the current second + * @property int $microsecondOfWeek The value of the microsecond starting from the beginning of the current week + * @property int $microsecondOfYear The value of the microsecond starting from the beginning of the current year + * @property int $millisecondOfCentury The value of the millisecond starting from the beginning of the current century + * @property int $millisecondOfDay The value of the millisecond starting from the beginning of the current day + * @property int $millisecondOfDecade The value of the millisecond starting from the beginning of the current decade + * @property int $millisecondOfHour The value of the millisecond starting from the beginning of the current hour + * @property int $millisecondOfMillennium The value of the millisecond starting from the beginning of the current millennium + * @property int $millisecondOfMinute The value of the millisecond starting from the beginning of the current minute + * @property int $millisecondOfMonth The value of the millisecond starting from the beginning of the current month + * @property int $millisecondOfQuarter The value of the millisecond starting from the beginning of the current quarter + * @property int $millisecondOfSecond The value of the millisecond starting from the beginning of the current second + * @property int $millisecondOfWeek The value of the millisecond starting from the beginning of the current week + * @property int $millisecondOfYear The value of the millisecond starting from the beginning of the current year + * @property int $minuteOfCentury The value of the minute starting from the beginning of the current century + * @property int $minuteOfDay The value of the minute starting from the beginning of the current day + * @property int $minuteOfDecade The value of the minute starting from the beginning of the current decade + * @property int $minuteOfHour The value of the minute starting from the beginning of the current hour + * @property int $minuteOfMillennium The value of the minute starting from the beginning of the current millennium + * @property int $minuteOfMonth The value of the minute starting from the beginning of the current month + * @property int $minuteOfQuarter The value of the minute starting from the beginning of the current quarter + * @property int $minuteOfWeek The value of the minute starting from the beginning of the current week + * @property int $minuteOfYear The value of the minute starting from the beginning of the current year + * @property int $monthOfCentury The value of the month starting from the beginning of the current century + * @property int $monthOfDecade The value of the month starting from the beginning of the current decade + * @property int $monthOfMillennium The value of the month starting from the beginning of the current millennium + * @property int $monthOfQuarter The value of the month starting from the beginning of the current quarter + * @property int $monthOfYear The value of the month starting from the beginning of the current year + * @property int $quarterOfCentury The value of the quarter starting from the beginning of the current century + * @property int $quarterOfDecade The value of the quarter starting from the beginning of the current decade + * @property int $quarterOfMillennium The value of the quarter starting from the beginning of the current millennium + * @property int $quarterOfYear The value of the quarter starting from the beginning of the current year + * @property int $secondOfCentury The value of the second starting from the beginning of the current century + * @property int $secondOfDay The value of the second starting from the beginning of the current day + * @property int $secondOfDecade The value of the second starting from the beginning of the current decade + * @property int $secondOfHour The value of the second starting from the beginning of the current hour + * @property int $secondOfMillennium The value of the second starting from the beginning of the current millennium + * @property int $secondOfMinute The value of the second starting from the beginning of the current minute + * @property int $secondOfMonth The value of the second starting from the beginning of the current month + * @property int $secondOfQuarter The value of the second starting from the beginning of the current quarter + * @property int $secondOfWeek The value of the second starting from the beginning of the current week + * @property int $secondOfYear The value of the second starting from the beginning of the current year + * @property int $weekOfCentury The value of the week starting from the beginning of the current century + * @property int $weekOfDecade The value of the week starting from the beginning of the current decade + * @property int $weekOfMillennium The value of the week starting from the beginning of the current millennium + * @property int $weekOfMonth 1 through 5 + * @property int $weekOfQuarter The value of the week starting from the beginning of the current quarter + * @property int $weekOfYear ISO-8601 week number of year, weeks starting on Monday + * @property int $yearOfCentury The value of the year starting from the beginning of the current century + * @property int $yearOfDecade The value of the year starting from the beginning of the current decade + * @property int $yearOfMillennium The value of the year starting from the beginning of the current millennium + * @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 $timezoneAbbreviatedName the current timezone abbreviated name + * @property-read string $tzAbbrName alias of $timezoneAbbreviatedName + * @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 $isoWeeksInYear 51 through 53 + * @property-read int $weekNumberInMonth 1 through 5 + * @property-read int $firstWeekDay 0 through 6 + * @property-read int $lastWeekDay 0 through 6 + * @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 $locale locale of the current instance + * @property-read int $centuriesInMillennium The number of centuries contained in the current millennium + * @property-read int $daysInCentury The number of days contained in the current century + * @property-read int $daysInDecade The number of days contained in the current decade + * @property-read int $daysInMillennium The number of days contained in the current millennium + * @property-read int $daysInMonth number of days in the given month + * @property-read int $daysInQuarter The number of days contained in the current quarter + * @property-read int $daysInWeek The number of days contained in the current week + * @property-read int $daysInYear 365 or 366 + * @property-read int $decadesInCentury The number of decades contained in the current century + * @property-read int $decadesInMillennium The number of decades contained in the current millennium + * @property-read int $hoursInCentury The number of hours contained in the current century + * @property-read int $hoursInDay The number of hours contained in the current day + * @property-read int $hoursInDecade The number of hours contained in the current decade + * @property-read int $hoursInMillennium The number of hours contained in the current millennium + * @property-read int $hoursInMonth The number of hours contained in the current month + * @property-read int $hoursInQuarter The number of hours contained in the current quarter + * @property-read int $hoursInWeek The number of hours contained in the current week + * @property-read int $hoursInYear The number of hours contained in the current year + * @property-read int $microsecondsInCentury The number of microseconds contained in the current century + * @property-read int $microsecondsInDay The number of microseconds contained in the current day + * @property-read int $microsecondsInDecade The number of microseconds contained in the current decade + * @property-read int $microsecondsInHour The number of microseconds contained in the current hour + * @property-read int $microsecondsInMillennium The number of microseconds contained in the current millennium + * @property-read int $microsecondsInMillisecond The number of microseconds contained in the current millisecond + * @property-read int $microsecondsInMinute The number of microseconds contained in the current minute + * @property-read int $microsecondsInMonth The number of microseconds contained in the current month + * @property-read int $microsecondsInQuarter The number of microseconds contained in the current quarter + * @property-read int $microsecondsInSecond The number of microseconds contained in the current second + * @property-read int $microsecondsInWeek The number of microseconds contained in the current week + * @property-read int $microsecondsInYear The number of microseconds contained in the current year + * @property-read int $millisecondsInCentury The number of milliseconds contained in the current century + * @property-read int $millisecondsInDay The number of milliseconds contained in the current day + * @property-read int $millisecondsInDecade The number of milliseconds contained in the current decade + * @property-read int $millisecondsInHour The number of milliseconds contained in the current hour + * @property-read int $millisecondsInMillennium The number of milliseconds contained in the current millennium + * @property-read int $millisecondsInMinute The number of milliseconds contained in the current minute + * @property-read int $millisecondsInMonth The number of milliseconds contained in the current month + * @property-read int $millisecondsInQuarter The number of milliseconds contained in the current quarter + * @property-read int $millisecondsInSecond The number of milliseconds contained in the current second + * @property-read int $millisecondsInWeek The number of milliseconds contained in the current week + * @property-read int $millisecondsInYear The number of milliseconds contained in the current year + * @property-read int $minutesInCentury The number of minutes contained in the current century + * @property-read int $minutesInDay The number of minutes contained in the current day + * @property-read int $minutesInDecade The number of minutes contained in the current decade + * @property-read int $minutesInHour The number of minutes contained in the current hour + * @property-read int $minutesInMillennium The number of minutes contained in the current millennium + * @property-read int $minutesInMonth The number of minutes contained in the current month + * @property-read int $minutesInQuarter The number of minutes contained in the current quarter + * @property-read int $minutesInWeek The number of minutes contained in the current week + * @property-read int $minutesInYear The number of minutes contained in the current year + * @property-read int $monthsInCentury The number of months contained in the current century + * @property-read int $monthsInDecade The number of months contained in the current decade + * @property-read int $monthsInMillennium The number of months contained in the current millennium + * @property-read int $monthsInQuarter The number of months contained in the current quarter + * @property-read int $monthsInYear The number of months contained in the current year + * @property-read int $quartersInCentury The number of quarters contained in the current century + * @property-read int $quartersInDecade The number of quarters contained in the current decade + * @property-read int $quartersInMillennium The number of quarters contained in the current millennium + * @property-read int $quartersInYear The number of quarters contained in the current year + * @property-read int $secondsInCentury The number of seconds contained in the current century + * @property-read int $secondsInDay The number of seconds contained in the current day + * @property-read int $secondsInDecade The number of seconds contained in the current decade + * @property-read int $secondsInHour The number of seconds contained in the current hour + * @property-read int $secondsInMillennium The number of seconds contained in the current millennium + * @property-read int $secondsInMinute The number of seconds contained in the current minute + * @property-read int $secondsInMonth The number of seconds contained in the current month + * @property-read int $secondsInQuarter The number of seconds contained in the current quarter + * @property-read int $secondsInWeek The number of seconds contained in the current week + * @property-read int $secondsInYear The number of seconds contained in the current year + * @property-read int $weeksInCentury The number of weeks contained in the current century + * @property-read int $weeksInDecade The number of weeks contained in the current decade + * @property-read int $weeksInMillennium The number of weeks contained in the current millennium + * @property-read int $weeksInMonth The number of weeks contained in the current month + * @property-read int $weeksInQuarter The number of weeks contained in the current quarter + * @property-read int $weeksInYear 51 through 53 + * @property-read int $yearsInCentury The number of years contained in the current century + * @property-read int $yearsInDecade The number of years contained in the current decade + * @property-read int $yearsInMillennium The number of years contained in the current millennium + * + * @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|string $date) 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 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 isSameWeek(DateTimeInterface|string $date) 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|string $date) 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|string $date) 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|string $date) 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|string $date) 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 isSameMilli(DateTimeInterface|string $date) Checks if the given date is in the same millisecond as the instance. If null passed, compare to now (with the same timezone). + * @method bool isCurrentMilli() Checks if the instance is in the same millisecond as the current moment. + * @method bool isNextMilli() Checks if the instance is in the same millisecond as the current moment next millisecond. + * @method bool isLastMilli() Checks if the instance is in the same millisecond as the current moment last millisecond. + * @method bool isSameMillisecond(DateTimeInterface|string $date) Checks if the given date is in the same millisecond as the instance. If null passed, compare to now (with the same timezone). + * @method bool isCurrentMillisecond() Checks if the instance is in the same millisecond as the current moment. + * @method bool isNextMillisecond() Checks if the instance is in the same millisecond as the current moment next millisecond. + * @method bool isLastMillisecond() Checks if the instance is in the same millisecond as the current moment last millisecond. + * @method bool isSameMicro(DateTimeInterface|string $date) 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|string $date) 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 isSameDecade(DateTimeInterface|string $date) 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|string $date) 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|string $date) 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 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 CarbonImmutable years(int $value, OverflowMode|bool|null $overflow = null, ?int $anchorDay = null) Set current instance year to the given value. + * @method CarbonImmutable year(int $value, OverflowMode|bool|null $overflow = null, ?int $anchorDay = null) Set current instance year to the given value. + * @method CarbonImmutable setYears(int $value, OverflowMode|bool|null $overflow = null, ?int $anchorDay = null) Set current instance year to the given value. + * @method CarbonImmutable setYear(int $value, OverflowMode|bool|null $overflow = null, ?int $anchorDay = null) Set current instance year to the given value. + * @method CarbonImmutable months(Month|int $value, OverflowMode|bool|null $overflow = null, ?int $anchorDay = null) Set current instance month to the given value. + * @method CarbonImmutable month(Month|int $value, OverflowMode|bool|null $overflow = null, ?int $anchorDay = null) Set current instance month to the given value. + * @method CarbonImmutable setMonths(Month|int $value, OverflowMode|bool|null $overflow = null, ?int $anchorDay = null) Set current instance month to the given value. + * @method CarbonImmutable setMonth(Month|int $value, OverflowMode|bool|null $overflow = null, ?int $anchorDay = null) Set current instance month to the given value. + * @method CarbonImmutable days(int $value) Set current instance day to the given value. + * @method CarbonImmutable day(int $value) Set current instance day to the given value. + * @method CarbonImmutable setDays(int $value) Set current instance day to the given value. + * @method CarbonImmutable setDay(int $value) Set current instance day to the given value. + * @method CarbonImmutable hours(int $value) Set current instance hour to the given value. + * @method CarbonImmutable hour(int $value) Set current instance hour to the given value. + * @method CarbonImmutable setHours(int $value) Set current instance hour to the given value. + * @method CarbonImmutable setHour(int $value) Set current instance hour to the given value. + * @method CarbonImmutable minutes(int $value) Set current instance minute to the given value. + * @method CarbonImmutable minute(int $value) Set current instance minute to the given value. + * @method CarbonImmutable setMinutes(int $value) Set current instance minute to the given value. + * @method CarbonImmutable setMinute(int $value) Set current instance minute to the given value. + * @method CarbonImmutable seconds(int $value) Set current instance second to the given value. + * @method CarbonImmutable second(int $value) Set current instance second to the given value. + * @method CarbonImmutable setSeconds(int $value) Set current instance second to the given value. + * @method CarbonImmutable setSecond(int $value) Set current instance second to the given value. + * @method CarbonImmutable millis(int $value) Set current instance millisecond to the given value. + * @method CarbonImmutable milli(int $value) Set current instance millisecond to the given value. + * @method CarbonImmutable setMillis(int $value) Set current instance millisecond to the given value. + * @method CarbonImmutable setMilli(int $value) Set current instance millisecond to the given value. + * @method CarbonImmutable milliseconds(int $value) Set current instance millisecond to the given value. + * @method CarbonImmutable millisecond(int $value) Set current instance millisecond to the given value. + * @method CarbonImmutable setMilliseconds(int $value) Set current instance millisecond to the given value. + * @method CarbonImmutable setMillisecond(int $value) Set current instance millisecond to the given value. + * @method CarbonImmutable micros(int $value) Set current instance microsecond to the given value. + * @method CarbonImmutable micro(int $value) Set current instance microsecond to the given value. + * @method CarbonImmutable setMicros(int $value) Set current instance microsecond to the given value. + * @method CarbonImmutable setMicro(int $value) Set current instance microsecond to the given value. + * @method CarbonImmutable microseconds(int $value) Set current instance microsecond to the given value. + * @method CarbonImmutable microsecond(int $value) Set current instance microsecond to the given value. + * @method CarbonImmutable setMicroseconds(int $value) Set current instance microsecond to the given value. + * @method self setMicrosecond(int $value) Set current instance microsecond to the given value. + * @method CarbonImmutable addYears(int|float $value = 1, ?int $anchorDay = null) Add years (the $value count passed in) to the instance (using date interval). + * @method CarbonImmutable addYear() Add one year to the instance (using date interval). + * @method CarbonImmutable subYears(int|float $value = 1, ?int $anchorDay = null) Sub years (the $value count passed in) to the instance (using date interval). + * @method CarbonImmutable subYear() Sub one year to the instance (using date interval). + * @method CarbonImmutable addYearsWithOverflow(int|float $value = 1) Add years (the $value count passed in) to the instance (using date interval) with overflow explicitly allowed. + * @method CarbonImmutable addYearWithOverflow() Add one year to the instance (using date interval) with overflow explicitly allowed. + * @method CarbonImmutable subYearsWithOverflow(int|float $value = 1) Sub years (the $value count passed in) to the instance (using date interval) with overflow explicitly allowed. + * @method CarbonImmutable subYearWithOverflow() Sub one year to the instance (using date interval) with overflow explicitly allowed. + * @method CarbonImmutable addYearsWithoutOverflow(int|float $value = 1, ?int $anchorDay = null) Add years (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonImmutable addYearWithoutOverflow() Add one year to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonImmutable subYearsWithoutOverflow(int|float $value = 1, ?int $anchorDay = null) Sub years (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonImmutable subYearWithoutOverflow() Sub one year to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonImmutable addYearsWithNoOverflow(int|float $value = 1, ?int $anchorDay = null) Add years (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonImmutable addYearWithNoOverflow() Add one year to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonImmutable subYearsWithNoOverflow(int|float $value = 1, ?int $anchorDay = null) Sub years (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonImmutable subYearWithNoOverflow() Sub one year to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonImmutable addYearsNoOverflow(int|float $value = 1, ?int $anchorDay = null) Add years (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonImmutable addYearNoOverflow() Add one year to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonImmutable subYearsNoOverflow(int|float $value = 1, ?int $anchorDay = null) Sub years (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonImmutable subYearNoOverflow() Sub one year to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonImmutable addMonths(int|float $value = 1, ?int $anchorDay = null) Add months (the $value count passed in) to the instance (using date interval). + * @method CarbonImmutable addMonth() Add one month to the instance (using date interval). + * @method CarbonImmutable subMonths(int|float $value = 1, ?int $anchorDay = null) Sub months (the $value count passed in) to the instance (using date interval). + * @method CarbonImmutable subMonth() Sub one month to the instance (using date interval). + * @method CarbonImmutable addMonthsWithOverflow(int|float $value = 1) Add months (the $value count passed in) to the instance (using date interval) with overflow explicitly allowed. + * @method CarbonImmutable addMonthWithOverflow() Add one month to the instance (using date interval) with overflow explicitly allowed. + * @method CarbonImmutable subMonthsWithOverflow(int|float $value = 1) Sub months (the $value count passed in) to the instance (using date interval) with overflow explicitly allowed. + * @method CarbonImmutable subMonthWithOverflow() Sub one month to the instance (using date interval) with overflow explicitly allowed. + * @method CarbonImmutable addMonthsWithoutOverflow(int|float $value = 1, ?int $anchorDay = null) Add months (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonImmutable addMonthWithoutOverflow() Add one month to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonImmutable subMonthsWithoutOverflow(int|float $value = 1, ?int $anchorDay = null) Sub months (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonImmutable subMonthWithoutOverflow() Sub one month to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonImmutable addMonthsWithNoOverflow(int|float $value = 1, ?int $anchorDay = null) Add months (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonImmutable addMonthWithNoOverflow() Add one month to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonImmutable subMonthsWithNoOverflow(int|float $value = 1, ?int $anchorDay = null) Sub months (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonImmutable subMonthWithNoOverflow() Sub one month to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonImmutable addMonthsNoOverflow(int|float $value = 1, ?int $anchorDay = null) Add months (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonImmutable addMonthNoOverflow() Add one month to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonImmutable subMonthsNoOverflow(int|float $value = 1, ?int $anchorDay = null) Sub months (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonImmutable subMonthNoOverflow() Sub one month to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonImmutable addDays(int|float $value = 1) Add days (the $value count passed in) to the instance (using date interval). + * @method CarbonImmutable addDay() Add one day to the instance (using date interval). + * @method CarbonImmutable subDays(int|float $value = 1) Sub days (the $value count passed in) to the instance (using date interval). + * @method CarbonImmutable subDay() Sub one day to the instance (using date interval). + * @method CarbonImmutable addHours(int|float $value = 1) Add hours (the $value count passed in) to the instance (using date interval). + * @method CarbonImmutable addHour() Add one hour to the instance (using date interval). + * @method CarbonImmutable subHours(int|float $value = 1) Sub hours (the $value count passed in) to the instance (using date interval). + * @method CarbonImmutable subHour() Sub one hour to the instance (using date interval). + * @method CarbonImmutable addMinutes(int|float $value = 1) Add minutes (the $value count passed in) to the instance (using date interval). + * @method CarbonImmutable addMinute() Add one minute to the instance (using date interval). + * @method CarbonImmutable subMinutes(int|float $value = 1) Sub minutes (the $value count passed in) to the instance (using date interval). + * @method CarbonImmutable subMinute() Sub one minute to the instance (using date interval). + * @method CarbonImmutable addSeconds(int|float $value = 1) Add seconds (the $value count passed in) to the instance (using date interval). + * @method CarbonImmutable addSecond() Add one second to the instance (using date interval). + * @method CarbonImmutable subSeconds(int|float $value = 1) Sub seconds (the $value count passed in) to the instance (using date interval). + * @method CarbonImmutable subSecond() Sub one second to the instance (using date interval). + * @method CarbonImmutable addMillis(int|float $value = 1) Add milliseconds (the $value count passed in) to the instance (using date interval). + * @method CarbonImmutable addMilli() Add one millisecond to the instance (using date interval). + * @method CarbonImmutable subMillis(int|float $value = 1) Sub milliseconds (the $value count passed in) to the instance (using date interval). + * @method CarbonImmutable subMilli() Sub one millisecond to the instance (using date interval). + * @method CarbonImmutable addMilliseconds(int|float $value = 1) Add milliseconds (the $value count passed in) to the instance (using date interval). + * @method CarbonImmutable addMillisecond() Add one millisecond to the instance (using date interval). + * @method CarbonImmutable subMilliseconds(int|float $value = 1) Sub milliseconds (the $value count passed in) to the instance (using date interval). + * @method CarbonImmutable subMillisecond() Sub one millisecond to the instance (using date interval). + * @method CarbonImmutable addMicros(int|float $value = 1) Add microseconds (the $value count passed in) to the instance (using date interval). + * @method CarbonImmutable addMicro() Add one microsecond to the instance (using date interval). + * @method CarbonImmutable subMicros(int|float $value = 1) Sub microseconds (the $value count passed in) to the instance (using date interval). + * @method CarbonImmutable subMicro() Sub one microsecond to the instance (using date interval). + * @method CarbonImmutable addMicroseconds(int|float $value = 1) Add microseconds (the $value count passed in) to the instance (using date interval). + * @method CarbonImmutable addMicrosecond() Add one microsecond to the instance (using date interval). + * @method CarbonImmutable subMicroseconds(int|float $value = 1) Sub microseconds (the $value count passed in) to the instance (using date interval). + * @method CarbonImmutable subMicrosecond() Sub one microsecond to the instance (using date interval). + * @method CarbonImmutable addMillennia(int|float $value = 1, ?int $anchorDay = null) Add millennia (the $value count passed in) to the instance (using date interval). + * @method CarbonImmutable addMillennium() Add one millennium to the instance (using date interval). + * @method CarbonImmutable subMillennia(int|float $value = 1, ?int $anchorDay = null) Sub millennia (the $value count passed in) to the instance (using date interval). + * @method CarbonImmutable subMillennium() Sub one millennium to the instance (using date interval). + * @method CarbonImmutable addMillenniaWithOverflow(int|float $value = 1) Add millennia (the $value count passed in) to the instance (using date interval) with overflow explicitly allowed. + * @method CarbonImmutable addMillenniumWithOverflow() Add one millennium to the instance (using date interval) with overflow explicitly allowed. + * @method CarbonImmutable subMillenniaWithOverflow(int|float $value = 1) Sub millennia (the $value count passed in) to the instance (using date interval) with overflow explicitly allowed. + * @method CarbonImmutable subMillenniumWithOverflow() Sub one millennium to the instance (using date interval) with overflow explicitly allowed. + * @method CarbonImmutable addMillenniaWithoutOverflow(int|float $value = 1, ?int $anchorDay = null) Add millennia (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonImmutable addMillenniumWithoutOverflow() Add one millennium to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonImmutable subMillenniaWithoutOverflow(int|float $value = 1, ?int $anchorDay = null) Sub millennia (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonImmutable subMillenniumWithoutOverflow() Sub one millennium to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonImmutable addMillenniaWithNoOverflow(int|float $value = 1, ?int $anchorDay = null) Add millennia (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonImmutable addMillenniumWithNoOverflow() Add one millennium to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonImmutable subMillenniaWithNoOverflow(int|float $value = 1, ?int $anchorDay = null) Sub millennia (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonImmutable subMillenniumWithNoOverflow() Sub one millennium to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonImmutable addMillenniaNoOverflow(int|float $value = 1, ?int $anchorDay = null) Add millennia (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonImmutable addMillenniumNoOverflow() Add one millennium to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonImmutable subMillenniaNoOverflow(int|float $value = 1, ?int $anchorDay = null) Sub millennia (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonImmutable subMillenniumNoOverflow() Sub one millennium to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonImmutable addCenturies(int|float $value = 1, ?int $anchorDay = null) Add centuries (the $value count passed in) to the instance (using date interval). + * @method CarbonImmutable addCentury() Add one century to the instance (using date interval). + * @method CarbonImmutable subCenturies(int|float $value = 1, ?int $anchorDay = null) Sub centuries (the $value count passed in) to the instance (using date interval). + * @method CarbonImmutable subCentury() Sub one century to the instance (using date interval). + * @method CarbonImmutable addCenturiesWithOverflow(int|float $value = 1) Add centuries (the $value count passed in) to the instance (using date interval) with overflow explicitly allowed. + * @method CarbonImmutable addCenturyWithOverflow() Add one century to the instance (using date interval) with overflow explicitly allowed. + * @method CarbonImmutable subCenturiesWithOverflow(int|float $value = 1) Sub centuries (the $value count passed in) to the instance (using date interval) with overflow explicitly allowed. + * @method CarbonImmutable subCenturyWithOverflow() Sub one century to the instance (using date interval) with overflow explicitly allowed. + * @method CarbonImmutable addCenturiesWithoutOverflow(int|float $value = 1, ?int $anchorDay = null) Add centuries (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonImmutable addCenturyWithoutOverflow() Add one century to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonImmutable subCenturiesWithoutOverflow(int|float $value = 1, ?int $anchorDay = null) Sub centuries (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonImmutable subCenturyWithoutOverflow() Sub one century to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonImmutable addCenturiesWithNoOverflow(int|float $value = 1, ?int $anchorDay = null) Add centuries (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonImmutable addCenturyWithNoOverflow() Add one century to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonImmutable subCenturiesWithNoOverflow(int|float $value = 1, ?int $anchorDay = null) Sub centuries (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonImmutable subCenturyWithNoOverflow() Sub one century to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonImmutable addCenturiesNoOverflow(int|float $value = 1, ?int $anchorDay = null) Add centuries (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonImmutable addCenturyNoOverflow() Add one century to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonImmutable subCenturiesNoOverflow(int|float $value = 1, ?int $anchorDay = null) Sub centuries (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonImmutable subCenturyNoOverflow() Sub one century to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonImmutable addDecades(int|float $value = 1, ?int $anchorDay = null) Add decades (the $value count passed in) to the instance (using date interval). + * @method CarbonImmutable addDecade() Add one decade to the instance (using date interval). + * @method CarbonImmutable subDecades(int|float $value = 1, ?int $anchorDay = null) Sub decades (the $value count passed in) to the instance (using date interval). + * @method CarbonImmutable subDecade() Sub one decade to the instance (using date interval). + * @method CarbonImmutable addDecadesWithOverflow(int|float $value = 1) Add decades (the $value count passed in) to the instance (using date interval) with overflow explicitly allowed. + * @method CarbonImmutable addDecadeWithOverflow() Add one decade to the instance (using date interval) with overflow explicitly allowed. + * @method CarbonImmutable subDecadesWithOverflow(int|float $value = 1) Sub decades (the $value count passed in) to the instance (using date interval) with overflow explicitly allowed. + * @method CarbonImmutable subDecadeWithOverflow() Sub one decade to the instance (using date interval) with overflow explicitly allowed. + * @method CarbonImmutable addDecadesWithoutOverflow(int|float $value = 1, ?int $anchorDay = null) Add decades (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonImmutable addDecadeWithoutOverflow() Add one decade to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonImmutable subDecadesWithoutOverflow(int|float $value = 1, ?int $anchorDay = null) Sub decades (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonImmutable subDecadeWithoutOverflow() Sub one decade to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonImmutable addDecadesWithNoOverflow(int|float $value = 1, ?int $anchorDay = null) Add decades (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonImmutable addDecadeWithNoOverflow() Add one decade to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonImmutable subDecadesWithNoOverflow(int|float $value = 1, ?int $anchorDay = null) Sub decades (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonImmutable subDecadeWithNoOverflow() Sub one decade to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonImmutable addDecadesNoOverflow(int|float $value = 1, ?int $anchorDay = null) Add decades (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonImmutable addDecadeNoOverflow() Add one decade to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonImmutable subDecadesNoOverflow(int|float $value = 1, ?int $anchorDay = null) Sub decades (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonImmutable subDecadeNoOverflow() Sub one decade to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonImmutable addQuarters(int|float $value = 1, ?int $anchorDay = null) Add quarters (the $value count passed in) to the instance (using date interval). + * @method CarbonImmutable addQuarter() Add one quarter to the instance (using date interval). + * @method CarbonImmutable subQuarters(int|float $value = 1, ?int $anchorDay = null) Sub quarters (the $value count passed in) to the instance (using date interval). + * @method CarbonImmutable subQuarter() Sub one quarter to the instance (using date interval). + * @method CarbonImmutable addQuartersWithOverflow(int|float $value = 1) Add quarters (the $value count passed in) to the instance (using date interval) with overflow explicitly allowed. + * @method CarbonImmutable addQuarterWithOverflow() Add one quarter to the instance (using date interval) with overflow explicitly allowed. + * @method CarbonImmutable subQuartersWithOverflow(int|float $value = 1) Sub quarters (the $value count passed in) to the instance (using date interval) with overflow explicitly allowed. + * @method CarbonImmutable subQuarterWithOverflow() Sub one quarter to the instance (using date interval) with overflow explicitly allowed. + * @method CarbonImmutable addQuartersWithoutOverflow(int|float $value = 1, ?int $anchorDay = null) Add quarters (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonImmutable addQuarterWithoutOverflow() Add one quarter to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonImmutable subQuartersWithoutOverflow(int|float $value = 1, ?int $anchorDay = null) Sub quarters (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonImmutable subQuarterWithoutOverflow() Sub one quarter to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonImmutable addQuartersWithNoOverflow(int|float $value = 1, ?int $anchorDay = null) Add quarters (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonImmutable addQuarterWithNoOverflow() Add one quarter to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonImmutable subQuartersWithNoOverflow(int|float $value = 1, ?int $anchorDay = null) Sub quarters (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonImmutable subQuarterWithNoOverflow() Sub one quarter to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonImmutable addQuartersNoOverflow(int|float $value = 1, ?int $anchorDay = null) Add quarters (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonImmutable addQuarterNoOverflow() Add one quarter to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonImmutable subQuartersNoOverflow(int|float $value = 1, ?int $anchorDay = null) Sub quarters (the $value count passed in) to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonImmutable subQuarterNoOverflow() Sub one quarter to the instance (using date interval) with overflow explicitly forbidden. + * @method CarbonImmutable addWeeks(int|float $value = 1) Add weeks (the $value count passed in) to the instance (using date interval). + * @method CarbonImmutable addWeek() Add one week to the instance (using date interval). + * @method CarbonImmutable subWeeks(int|float $value = 1) Sub weeks (the $value count passed in) to the instance (using date interval). + * @method CarbonImmutable subWeek() Sub one week to the instance (using date interval). + * @method CarbonImmutable addWeekdays(int|float $value = 1) Add weekdays (the $value count passed in) to the instance (using date interval). + * @method CarbonImmutable addWeekday() Add one weekday to the instance (using date interval). + * @method CarbonImmutable subWeekdays(int|float $value = 1) Sub weekdays (the $value count passed in) to the instance (using date interval). + * @method CarbonImmutable subWeekday() Sub one weekday to the instance (using date interval). + * @method CarbonImmutable addUTCMicros(int|float $value = 1) Add microseconds (the $value count passed in) to the instance (using timestamp). + * @method CarbonImmutable addUTCMicro() Add one microsecond to the instance (using timestamp). + * @method CarbonImmutable subUTCMicros(int|float $value = 1) Sub microseconds (the $value count passed in) to the instance (using timestamp). + * @method CarbonImmutable subUTCMicro() Sub one microsecond to the instance (using timestamp). + * @method CarbonPeriod microsUntil($endDate = null, int|float $factor = 1) Return an iterable period from current date to given end (string, DateTime or Carbon instance) for each microsecond or every X microseconds if a factor is given. + * @method float diffInUTCMicros(DateTimeInterface|string|null $date, bool $absolute = false) Convert current and given date in UTC timezone and return a floating number of microseconds. + * @method CarbonImmutable addUTCMicroseconds(int|float $value = 1) Add microseconds (the $value count passed in) to the instance (using timestamp). + * @method CarbonImmutable addUTCMicrosecond() Add one microsecond to the instance (using timestamp). + * @method CarbonImmutable subUTCMicroseconds(int|float $value = 1) Sub microseconds (the $value count passed in) to the instance (using timestamp). + * @method CarbonImmutable subUTCMicrosecond() Sub one microsecond to the instance (using timestamp). + * @method CarbonPeriod microsecondsUntil($endDate = null, int|float $factor = 1) Return an iterable period from current date to given end (string, DateTime or Carbon instance) for each microsecond or every X microseconds if a factor is given. + * @method float diffInUTCMicroseconds(DateTimeInterface|string|null $date, bool $absolute = false) Convert current and given date in UTC timezone and return a floating number of microseconds. + * @method CarbonImmutable addUTCMillis(int|float $value = 1) Add milliseconds (the $value count passed in) to the instance (using timestamp). + * @method CarbonImmutable addUTCMilli() Add one millisecond to the instance (using timestamp). + * @method CarbonImmutable subUTCMillis(int|float $value = 1) Sub milliseconds (the $value count passed in) to the instance (using timestamp). + * @method CarbonImmutable subUTCMilli() Sub one millisecond to the instance (using timestamp). + * @method CarbonPeriod millisUntil($endDate = null, int|float $factor = 1) Return an iterable period from current date to given end (string, DateTime or Carbon instance) for each millisecond or every X milliseconds if a factor is given. + * @method float diffInUTCMillis(DateTimeInterface|string|null $date, bool $absolute = false) Convert current and given date in UTC timezone and return a floating number of milliseconds. + * @method CarbonImmutable addUTCMilliseconds(int|float $value = 1) Add milliseconds (the $value count passed in) to the instance (using timestamp). + * @method CarbonImmutable addUTCMillisecond() Add one millisecond to the instance (using timestamp). + * @method CarbonImmutable subUTCMilliseconds(int|float $value = 1) Sub milliseconds (the $value count passed in) to the instance (using timestamp). + * @method CarbonImmutable subUTCMillisecond() Sub one millisecond to the instance (using timestamp). + * @method CarbonPeriod millisecondsUntil($endDate = null, int|float $factor = 1) Return an iterable period from current date to given end (string, DateTime or Carbon instance) for each millisecond or every X milliseconds if a factor is given. + * @method float diffInUTCMilliseconds(DateTimeInterface|string|null $date, bool $absolute = false) Convert current and given date in UTC timezone and return a floating number of milliseconds. + * @method CarbonImmutable addUTCSeconds(int|float $value = 1) Add seconds (the $value count passed in) to the instance (using timestamp). + * @method CarbonImmutable addUTCSecond() Add one second to the instance (using timestamp). + * @method CarbonImmutable subUTCSeconds(int|float $value = 1) Sub seconds (the $value count passed in) to the instance (using timestamp). + * @method CarbonImmutable subUTCSecond() Sub one second to the instance (using timestamp). + * @method CarbonPeriod secondsUntil($endDate = null, int|float $factor = 1) Return an iterable period from current date to given end (string, DateTime or Carbon instance) for each second or every X seconds if a factor is given. + * @method float diffInUTCSeconds(DateTimeInterface|string|null $date, bool $absolute = false) Convert current and given date in UTC timezone and return a floating number of seconds. + * @method CarbonImmutable addUTCMinutes(int|float $value = 1) Add minutes (the $value count passed in) to the instance (using timestamp). + * @method CarbonImmutable addUTCMinute() Add one minute to the instance (using timestamp). + * @method CarbonImmutable subUTCMinutes(int|float $value = 1) Sub minutes (the $value count passed in) to the instance (using timestamp). + * @method CarbonImmutable subUTCMinute() Sub one minute to the instance (using timestamp). + * @method CarbonPeriod minutesUntil($endDate = null, int|float $factor = 1) Return an iterable period from current date to given end (string, DateTime or Carbon instance) for each minute or every X minutes if a factor is given. + * @method float diffInUTCMinutes(DateTimeInterface|string|null $date, bool $absolute = false) Convert current and given date in UTC timezone and return a floating number of minutes. + * @method CarbonImmutable addUTCHours(int|float $value = 1) Add hours (the $value count passed in) to the instance (using timestamp). + * @method CarbonImmutable addUTCHour() Add one hour to the instance (using timestamp). + * @method CarbonImmutable subUTCHours(int|float $value = 1) Sub hours (the $value count passed in) to the instance (using timestamp). + * @method CarbonImmutable subUTCHour() Sub one hour to the instance (using timestamp). + * @method CarbonPeriod hoursUntil($endDate = null, int|float $factor = 1) Return an iterable period from current date to given end (string, DateTime or Carbon instance) for each hour or every X hours if a factor is given. + * @method float diffInUTCHours(DateTimeInterface|string|null $date, bool $absolute = false) Convert current and given date in UTC timezone and return a floating number of hours. + * @method CarbonImmutable addUTCDays(int|float $value = 1) Add days (the $value count passed in) to the instance (using timestamp). + * @method CarbonImmutable addUTCDay() Add one day to the instance (using timestamp). + * @method CarbonImmutable subUTCDays(int|float $value = 1) Sub days (the $value count passed in) to the instance (using timestamp). + * @method CarbonImmutable subUTCDay() Sub one day to the instance (using timestamp). + * @method CarbonPeriod daysUntil($endDate = null, int|float $factor = 1) Return an iterable period from current date to given end (string, DateTime or Carbon instance) for each day or every X days if a factor is given. + * @method float diffInUTCDays(DateTimeInterface|string|null $date, bool $absolute = false) Convert current and given date in UTC timezone and return a floating number of days. + * @method CarbonImmutable addUTCWeeks(int|float $value = 1) Add weeks (the $value count passed in) to the instance (using timestamp). + * @method CarbonImmutable addUTCWeek() Add one week to the instance (using timestamp). + * @method CarbonImmutable subUTCWeeks(int|float $value = 1) Sub weeks (the $value count passed in) to the instance (using timestamp). + * @method CarbonImmutable subUTCWeek() Sub one week to the instance (using timestamp). + * @method CarbonPeriod weeksUntil($endDate = null, int|float $factor = 1) Return an iterable period from current date to given end (string, DateTime or Carbon instance) for each week or every X weeks if a factor is given. + * @method float diffInUTCWeeks(DateTimeInterface|string|null $date, bool $absolute = false) Convert current and given date in UTC timezone and return a floating number of weeks. + * @method CarbonImmutable addUTCMonths(int|float $value = 1) Add months (the $value count passed in) to the instance (using timestamp). + * @method CarbonImmutable addUTCMonth() Add one month to the instance (using timestamp). + * @method CarbonImmutable subUTCMonths(int|float $value = 1) Sub months (the $value count passed in) to the instance (using timestamp). + * @method CarbonImmutable subUTCMonth() Sub one month to the instance (using timestamp). + * @method CarbonPeriod monthsUntil($endDate = null, int|float $factor = 1) Return an iterable period from current date to given end (string, DateTime or Carbon instance) for each month or every X months if a factor is given. + * @method float diffInUTCMonths(DateTimeInterface|string|null $date, bool $absolute = false) Convert current and given date in UTC timezone and return a floating number of months. + * @method CarbonImmutable addUTCQuarters(int|float $value = 1) Add quarters (the $value count passed in) to the instance (using timestamp). + * @method CarbonImmutable addUTCQuarter() Add one quarter to the instance (using timestamp). + * @method CarbonImmutable subUTCQuarters(int|float $value = 1) Sub quarters (the $value count passed in) to the instance (using timestamp). + * @method CarbonImmutable subUTCQuarter() Sub one quarter to the instance (using timestamp). + * @method CarbonPeriod quartersUntil($endDate = null, int|float $factor = 1) Return an iterable period from current date to given end (string, DateTime or Carbon instance) for each quarter or every X quarters if a factor is given. + * @method float diffInUTCQuarters(DateTimeInterface|string|null $date, bool $absolute = false) Convert current and given date in UTC timezone and return a floating number of quarters. + * @method CarbonImmutable addUTCYears(int|float $value = 1) Add years (the $value count passed in) to the instance (using timestamp). + * @method CarbonImmutable addUTCYear() Add one year to the instance (using timestamp). + * @method CarbonImmutable subUTCYears(int|float $value = 1) Sub years (the $value count passed in) to the instance (using timestamp). + * @method CarbonImmutable subUTCYear() Sub one year to the instance (using timestamp). + * @method CarbonPeriod yearsUntil($endDate = null, int|float $factor = 1) Return an iterable period from current date to given end (string, DateTime or Carbon instance) for each year or every X years if a factor is given. + * @method float diffInUTCYears(DateTimeInterface|string|null $date, bool $absolute = false) Convert current and given date in UTC timezone and return a floating number of years. + * @method CarbonImmutable addUTCDecades(int|float $value = 1) Add decades (the $value count passed in) to the instance (using timestamp). + * @method CarbonImmutable addUTCDecade() Add one decade to the instance (using timestamp). + * @method CarbonImmutable subUTCDecades(int|float $value = 1) Sub decades (the $value count passed in) to the instance (using timestamp). + * @method CarbonImmutable subUTCDecade() Sub one decade to the instance (using timestamp). + * @method CarbonPeriod decadesUntil($endDate = null, int|float $factor = 1) Return an iterable period from current date to given end (string, DateTime or Carbon instance) for each decade or every X decades if a factor is given. + * @method float diffInUTCDecades(DateTimeInterface|string|null $date, bool $absolute = false) Convert current and given date in UTC timezone and return a floating number of decades. + * @method CarbonImmutable addUTCCenturies(int|float $value = 1) Add centuries (the $value count passed in) to the instance (using timestamp). + * @method CarbonImmutable addUTCCentury() Add one century to the instance (using timestamp). + * @method CarbonImmutable subUTCCenturies(int|float $value = 1) Sub centuries (the $value count passed in) to the instance (using timestamp). + * @method CarbonImmutable subUTCCentury() Sub one century to the instance (using timestamp). + * @method CarbonPeriod centuriesUntil($endDate = null, int|float $factor = 1) Return an iterable period from current date to given end (string, DateTime or Carbon instance) for each century or every X centuries if a factor is given. + * @method float diffInUTCCenturies(DateTimeInterface|string|null $date, bool $absolute = false) Convert current and given date in UTC timezone and return a floating number of centuries. + * @method CarbonImmutable addUTCMillennia(int|float $value = 1) Add millennia (the $value count passed in) to the instance (using timestamp). + * @method CarbonImmutable addUTCMillennium() Add one millennium to the instance (using timestamp). + * @method CarbonImmutable subUTCMillennia(int|float $value = 1) Sub millennia (the $value count passed in) to the instance (using timestamp). + * @method CarbonImmutable subUTCMillennium() Sub one millennium to the instance (using timestamp). + * @method CarbonPeriod millenniaUntil($endDate = null, int|float $factor = 1) Return an iterable period from current date to given end (string, DateTime or Carbon instance) for each millennium or every X millennia if a factor is given. + * @method float diffInUTCMillennia(DateTimeInterface|string|null $date, bool $absolute = false) Convert current and given date in UTC timezone and return a floating number of millennia. + * @method CarbonImmutable roundYear(float $precision = 1, string $function = "round") Round the current instance year with given precision using the given function. + * @method CarbonImmutable roundYears(float $precision = 1, string $function = "round") Round the current instance year with given precision using the given function. + * @method CarbonImmutable floorYear(float $precision = 1) Truncate the current instance year with given precision. + * @method CarbonImmutable floorYears(float $precision = 1) Truncate the current instance year with given precision. + * @method CarbonImmutable ceilYear(float $precision = 1) Ceil the current instance year with given precision. + * @method CarbonImmutable ceilYears(float $precision = 1) Ceil the current instance year with given precision. + * @method CarbonImmutable roundMonth(float $precision = 1, string $function = "round") Round the current instance month with given precision using the given function. + * @method CarbonImmutable roundMonths(float $precision = 1, string $function = "round") Round the current instance month with given precision using the given function. + * @method CarbonImmutable floorMonth(float $precision = 1) Truncate the current instance month with given precision. + * @method CarbonImmutable floorMonths(float $precision = 1) Truncate the current instance month with given precision. + * @method CarbonImmutable ceilMonth(float $precision = 1) Ceil the current instance month with given precision. + * @method CarbonImmutable ceilMonths(float $precision = 1) Ceil the current instance month with given precision. + * @method CarbonImmutable roundDay(float $precision = 1, string $function = "round") Round the current instance day with given precision using the given function. + * @method CarbonImmutable roundDays(float $precision = 1, string $function = "round") Round the current instance day with given precision using the given function. + * @method CarbonImmutable floorDay(float $precision = 1) Truncate the current instance day with given precision. + * @method CarbonImmutable floorDays(float $precision = 1) Truncate the current instance day with given precision. + * @method CarbonImmutable ceilDay(float $precision = 1) Ceil the current instance day with given precision. + * @method CarbonImmutable ceilDays(float $precision = 1) Ceil the current instance day with given precision. + * @method CarbonImmutable roundHour(float $precision = 1, string $function = "round") Round the current instance hour with given precision using the given function. + * @method CarbonImmutable roundHours(float $precision = 1, string $function = "round") Round the current instance hour with given precision using the given function. + * @method CarbonImmutable floorHour(float $precision = 1) Truncate the current instance hour with given precision. + * @method CarbonImmutable floorHours(float $precision = 1) Truncate the current instance hour with given precision. + * @method CarbonImmutable ceilHour(float $precision = 1) Ceil the current instance hour with given precision. + * @method CarbonImmutable ceilHours(float $precision = 1) Ceil the current instance hour with given precision. + * @method CarbonImmutable roundMinute(float $precision = 1, string $function = "round") Round the current instance minute with given precision using the given function. + * @method CarbonImmutable roundMinutes(float $precision = 1, string $function = "round") Round the current instance minute with given precision using the given function. + * @method CarbonImmutable floorMinute(float $precision = 1) Truncate the current instance minute with given precision. + * @method CarbonImmutable floorMinutes(float $precision = 1) Truncate the current instance minute with given precision. + * @method CarbonImmutable ceilMinute(float $precision = 1) Ceil the current instance minute with given precision. + * @method CarbonImmutable ceilMinutes(float $precision = 1) Ceil the current instance minute with given precision. + * @method CarbonImmutable roundSecond(float $precision = 1, string $function = "round") Round the current instance second with given precision using the given function. + * @method CarbonImmutable roundSeconds(float $precision = 1, string $function = "round") Round the current instance second with given precision using the given function. + * @method CarbonImmutable floorSecond(float $precision = 1) Truncate the current instance second with given precision. + * @method CarbonImmutable floorSeconds(float $precision = 1) Truncate the current instance second with given precision. + * @method CarbonImmutable ceilSecond(float $precision = 1) Ceil the current instance second with given precision. + * @method CarbonImmutable ceilSeconds(float $precision = 1) Ceil the current instance second with given precision. + * @method CarbonImmutable roundMillennium(float $precision = 1, string $function = "round") Round the current instance millennium with given precision using the given function. + * @method CarbonImmutable roundMillennia(float $precision = 1, string $function = "round") Round the current instance millennium with given precision using the given function. + * @method CarbonImmutable floorMillennium(float $precision = 1) Truncate the current instance millennium with given precision. + * @method CarbonImmutable floorMillennia(float $precision = 1) Truncate the current instance millennium with given precision. + * @method CarbonImmutable ceilMillennium(float $precision = 1) Ceil the current instance millennium with given precision. + * @method CarbonImmutable ceilMillennia(float $precision = 1) Ceil the current instance millennium with given precision. + * @method CarbonImmutable roundCentury(float $precision = 1, string $function = "round") Round the current instance century with given precision using the given function. + * @method CarbonImmutable roundCenturies(float $precision = 1, string $function = "round") Round the current instance century with given precision using the given function. + * @method CarbonImmutable floorCentury(float $precision = 1) Truncate the current instance century with given precision. + * @method CarbonImmutable floorCenturies(float $precision = 1) Truncate the current instance century with given precision. + * @method CarbonImmutable ceilCentury(float $precision = 1) Ceil the current instance century with given precision. + * @method CarbonImmutable ceilCenturies(float $precision = 1) Ceil the current instance century with given precision. + * @method CarbonImmutable roundDecade(float $precision = 1, string $function = "round") Round the current instance decade with given precision using the given function. + * @method CarbonImmutable roundDecades(float $precision = 1, string $function = "round") Round the current instance decade with given precision using the given function. + * @method CarbonImmutable floorDecade(float $precision = 1) Truncate the current instance decade with given precision. + * @method CarbonImmutable floorDecades(float $precision = 1) Truncate the current instance decade with given precision. + * @method CarbonImmutable ceilDecade(float $precision = 1) Ceil the current instance decade with given precision. + * @method CarbonImmutable ceilDecades(float $precision = 1) Ceil the current instance decade with given precision. + * @method CarbonImmutable roundQuarter(float $precision = 1, string $function = "round") Round the current instance quarter with given precision using the given function. + * @method CarbonImmutable roundQuarters(float $precision = 1, string $function = "round") Round the current instance quarter with given precision using the given function. + * @method CarbonImmutable floorQuarter(float $precision = 1) Truncate the current instance quarter with given precision. + * @method CarbonImmutable floorQuarters(float $precision = 1) Truncate the current instance quarter with given precision. + * @method CarbonImmutable ceilQuarter(float $precision = 1) Ceil the current instance quarter with given precision. + * @method CarbonImmutable ceilQuarters(float $precision = 1) Ceil the current instance quarter with given precision. + * @method CarbonImmutable roundMillisecond(float $precision = 1, string $function = "round") Round the current instance millisecond with given precision using the given function. + * @method CarbonImmutable roundMilliseconds(float $precision = 1, string $function = "round") Round the current instance millisecond with given precision using the given function. + * @method CarbonImmutable floorMillisecond(float $precision = 1) Truncate the current instance millisecond with given precision. + * @method CarbonImmutable floorMilliseconds(float $precision = 1) Truncate the current instance millisecond with given precision. + * @method CarbonImmutable ceilMillisecond(float $precision = 1) Ceil the current instance millisecond with given precision. + * @method CarbonImmutable ceilMilliseconds(float $precision = 1) Ceil the current instance millisecond with given precision. + * @method CarbonImmutable roundMicrosecond(float $precision = 1, string $function = "round") Round the current instance microsecond with given precision using the given function. + * @method CarbonImmutable roundMicroseconds(float $precision = 1, string $function = "round") Round the current instance microsecond with given precision using the given function. + * @method CarbonImmutable floorMicrosecond(float $precision = 1) Truncate the current instance microsecond with given precision. + * @method CarbonImmutable floorMicroseconds(float $precision = 1) Truncate the current instance microsecond with given precision. + * @method CarbonImmutable ceilMicrosecond(float $precision = 1) Ceil the current instance microsecond with given precision. + * @method CarbonImmutable 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.) + * @method int centuriesInMillennium() Return the number of centuries contained in the current millennium + * @method int|static centuryOfMillennium(?int $century = null) Return the value of the century starting from the beginning of the current millennium when called with no parameters, change the current century when called with an integer value + * @method int|static dayOfCentury(?int $day = null) Return the value of the day starting from the beginning of the current century when called with no parameters, change the current day when called with an integer value + * @method int|static dayOfDecade(?int $day = null) Return the value of the day starting from the beginning of the current decade when called with no parameters, change the current day when called with an integer value + * @method int|static dayOfMillennium(?int $day = null) Return the value of the day starting from the beginning of the current millennium when called with no parameters, change the current day when called with an integer value + * @method int|static dayOfMonth(?int $day = null) Return the value of the day starting from the beginning of the current month when called with no parameters, change the current day when called with an integer value + * @method int|static dayOfQuarter(?int $day = null) Return the value of the day starting from the beginning of the current quarter when called with no parameters, change the current day when called with an integer value + * @method int|static dayOfWeek(?int $day = null) Return the value of the day starting from the beginning of the current week when called with no parameters, change the current day when called with an integer value + * @method int daysInCentury() Return the number of days contained in the current century + * @method int daysInDecade() Return the number of days contained in the current decade + * @method int daysInMillennium() Return the number of days contained in the current millennium + * @method int daysInMonth() Return the number of days contained in the current month + * @method int daysInQuarter() Return the number of days contained in the current quarter + * @method int daysInWeek() Return the number of days contained in the current week + * @method int daysInYear() Return the number of days contained in the current year + * @method int|static decadeOfCentury(?int $decade = null) Return the value of the decade starting from the beginning of the current century when called with no parameters, change the current decade when called with an integer value + * @method int|static decadeOfMillennium(?int $decade = null) Return the value of the decade starting from the beginning of the current millennium when called with no parameters, change the current decade when called with an integer value + * @method int decadesInCentury() Return the number of decades contained in the current century + * @method int decadesInMillennium() Return the number of decades contained in the current millennium + * @method int|static hourOfCentury(?int $hour = null) Return the value of the hour starting from the beginning of the current century when called with no parameters, change the current hour when called with an integer value + * @method int|static hourOfDay(?int $hour = null) Return the value of the hour starting from the beginning of the current day when called with no parameters, change the current hour when called with an integer value + * @method int|static hourOfDecade(?int $hour = null) Return the value of the hour starting from the beginning of the current decade when called with no parameters, change the current hour when called with an integer value + * @method int|static hourOfMillennium(?int $hour = null) Return the value of the hour starting from the beginning of the current millennium when called with no parameters, change the current hour when called with an integer value + * @method int|static hourOfMonth(?int $hour = null) Return the value of the hour starting from the beginning of the current month when called with no parameters, change the current hour when called with an integer value + * @method int|static hourOfQuarter(?int $hour = null) Return the value of the hour starting from the beginning of the current quarter when called with no parameters, change the current hour when called with an integer value + * @method int|static hourOfWeek(?int $hour = null) Return the value of the hour starting from the beginning of the current week when called with no parameters, change the current hour when called with an integer value + * @method int|static hourOfYear(?int $hour = null) Return the value of the hour starting from the beginning of the current year when called with no parameters, change the current hour when called with an integer value + * @method int hoursInCentury() Return the number of hours contained in the current century + * @method int hoursInDay() Return the number of hours contained in the current day + * @method int hoursInDecade() Return the number of hours contained in the current decade + * @method int hoursInMillennium() Return the number of hours contained in the current millennium + * @method int hoursInMonth() Return the number of hours contained in the current month + * @method int hoursInQuarter() Return the number of hours contained in the current quarter + * @method int hoursInWeek() Return the number of hours contained in the current week + * @method int hoursInYear() Return the number of hours contained in the current year + * @method int|static microsecondOfCentury(?int $microsecond = null) Return the value of the microsecond starting from the beginning of the current century when called with no parameters, change the current microsecond when called with an integer value + * @method int|static microsecondOfDay(?int $microsecond = null) Return the value of the microsecond starting from the beginning of the current day when called with no parameters, change the current microsecond when called with an integer value + * @method int|static microsecondOfDecade(?int $microsecond = null) Return the value of the microsecond starting from the beginning of the current decade when called with no parameters, change the current microsecond when called with an integer value + * @method int|static microsecondOfHour(?int $microsecond = null) Return the value of the microsecond starting from the beginning of the current hour when called with no parameters, change the current microsecond when called with an integer value + * @method int|static microsecondOfMillennium(?int $microsecond = null) Return the value of the microsecond starting from the beginning of the current millennium when called with no parameters, change the current microsecond when called with an integer value + * @method int|static microsecondOfMillisecond(?int $microsecond = null) Return the value of the microsecond starting from the beginning of the current millisecond when called with no parameters, change the current microsecond when called with an integer value + * @method int|static microsecondOfMinute(?int $microsecond = null) Return the value of the microsecond starting from the beginning of the current minute when called with no parameters, change the current microsecond when called with an integer value + * @method int|static microsecondOfMonth(?int $microsecond = null) Return the value of the microsecond starting from the beginning of the current month when called with no parameters, change the current microsecond when called with an integer value + * @method int|static microsecondOfQuarter(?int $microsecond = null) Return the value of the microsecond starting from the beginning of the current quarter when called with no parameters, change the current microsecond when called with an integer value + * @method int|static microsecondOfSecond(?int $microsecond = null) Return the value of the microsecond starting from the beginning of the current second when called with no parameters, change the current microsecond when called with an integer value + * @method int|static microsecondOfWeek(?int $microsecond = null) Return the value of the microsecond starting from the beginning of the current week when called with no parameters, change the current microsecond when called with an integer value + * @method int|static microsecondOfYear(?int $microsecond = null) Return the value of the microsecond starting from the beginning of the current year when called with no parameters, change the current microsecond when called with an integer value + * @method int microsecondsInCentury() Return the number of microseconds contained in the current century + * @method int microsecondsInDay() Return the number of microseconds contained in the current day + * @method int microsecondsInDecade() Return the number of microseconds contained in the current decade + * @method int microsecondsInHour() Return the number of microseconds contained in the current hour + * @method int microsecondsInMillennium() Return the number of microseconds contained in the current millennium + * @method int microsecondsInMillisecond() Return the number of microseconds contained in the current millisecond + * @method int microsecondsInMinute() Return the number of microseconds contained in the current minute + * @method int microsecondsInMonth() Return the number of microseconds contained in the current month + * @method int microsecondsInQuarter() Return the number of microseconds contained in the current quarter + * @method int microsecondsInSecond() Return the number of microseconds contained in the current second + * @method int microsecondsInWeek() Return the number of microseconds contained in the current week + * @method int microsecondsInYear() Return the number of microseconds contained in the current year + * @method int|static millisecondOfCentury(?int $millisecond = null) Return the value of the millisecond starting from the beginning of the current century when called with no parameters, change the current millisecond when called with an integer value + * @method int|static millisecondOfDay(?int $millisecond = null) Return the value of the millisecond starting from the beginning of the current day when called with no parameters, change the current millisecond when called with an integer value + * @method int|static millisecondOfDecade(?int $millisecond = null) Return the value of the millisecond starting from the beginning of the current decade when called with no parameters, change the current millisecond when called with an integer value + * @method int|static millisecondOfHour(?int $millisecond = null) Return the value of the millisecond starting from the beginning of the current hour when called with no parameters, change the current millisecond when called with an integer value + * @method int|static millisecondOfMillennium(?int $millisecond = null) Return the value of the millisecond starting from the beginning of the current millennium when called with no parameters, change the current millisecond when called with an integer value + * @method int|static millisecondOfMinute(?int $millisecond = null) Return the value of the millisecond starting from the beginning of the current minute when called with no parameters, change the current millisecond when called with an integer value + * @method int|static millisecondOfMonth(?int $millisecond = null) Return the value of the millisecond starting from the beginning of the current month when called with no parameters, change the current millisecond when called with an integer value + * @method int|static millisecondOfQuarter(?int $millisecond = null) Return the value of the millisecond starting from the beginning of the current quarter when called with no parameters, change the current millisecond when called with an integer value + * @method int|static millisecondOfSecond(?int $millisecond = null) Return the value of the millisecond starting from the beginning of the current second when called with no parameters, change the current millisecond when called with an integer value + * @method int|static millisecondOfWeek(?int $millisecond = null) Return the value of the millisecond starting from the beginning of the current week when called with no parameters, change the current millisecond when called with an integer value + * @method int|static millisecondOfYear(?int $millisecond = null) Return the value of the millisecond starting from the beginning of the current year when called with no parameters, change the current millisecond when called with an integer value + * @method int millisecondsInCentury() Return the number of milliseconds contained in the current century + * @method int millisecondsInDay() Return the number of milliseconds contained in the current day + * @method int millisecondsInDecade() Return the number of milliseconds contained in the current decade + * @method int millisecondsInHour() Return the number of milliseconds contained in the current hour + * @method int millisecondsInMillennium() Return the number of milliseconds contained in the current millennium + * @method int millisecondsInMinute() Return the number of milliseconds contained in the current minute + * @method int millisecondsInMonth() Return the number of milliseconds contained in the current month + * @method int millisecondsInQuarter() Return the number of milliseconds contained in the current quarter + * @method int millisecondsInSecond() Return the number of milliseconds contained in the current second + * @method int millisecondsInWeek() Return the number of milliseconds contained in the current week + * @method int millisecondsInYear() Return the number of milliseconds contained in the current year + * @method int|static minuteOfCentury(?int $minute = null) Return the value of the minute starting from the beginning of the current century when called with no parameters, change the current minute when called with an integer value + * @method int|static minuteOfDay(?int $minute = null) Return the value of the minute starting from the beginning of the current day when called with no parameters, change the current minute when called with an integer value + * @method int|static minuteOfDecade(?int $minute = null) Return the value of the minute starting from the beginning of the current decade when called with no parameters, change the current minute when called with an integer value + * @method int|static minuteOfHour(?int $minute = null) Return the value of the minute starting from the beginning of the current hour when called with no parameters, change the current minute when called with an integer value + * @method int|static minuteOfMillennium(?int $minute = null) Return the value of the minute starting from the beginning of the current millennium when called with no parameters, change the current minute when called with an integer value + * @method int|static minuteOfMonth(?int $minute = null) Return the value of the minute starting from the beginning of the current month when called with no parameters, change the current minute when called with an integer value + * @method int|static minuteOfQuarter(?int $minute = null) Return the value of the minute starting from the beginning of the current quarter when called with no parameters, change the current minute when called with an integer value + * @method int|static minuteOfWeek(?int $minute = null) Return the value of the minute starting from the beginning of the current week when called with no parameters, change the current minute when called with an integer value + * @method int|static minuteOfYear(?int $minute = null) Return the value of the minute starting from the beginning of the current year when called with no parameters, change the current minute when called with an integer value + * @method int minutesInCentury() Return the number of minutes contained in the current century + * @method int minutesInDay() Return the number of minutes contained in the current day + * @method int minutesInDecade() Return the number of minutes contained in the current decade + * @method int minutesInHour() Return the number of minutes contained in the current hour + * @method int minutesInMillennium() Return the number of minutes contained in the current millennium + * @method int minutesInMonth() Return the number of minutes contained in the current month + * @method int minutesInQuarter() Return the number of minutes contained in the current quarter + * @method int minutesInWeek() Return the number of minutes contained in the current week + * @method int minutesInYear() Return the number of minutes contained in the current year + * @method int|static monthOfCentury(?int $month = null) Return the value of the month starting from the beginning of the current century when called with no parameters, change the current month when called with an integer value + * @method int|static monthOfDecade(?int $month = null) Return the value of the month starting from the beginning of the current decade when called with no parameters, change the current month when called with an integer value + * @method int|static monthOfMillennium(?int $month = null) Return the value of the month starting from the beginning of the current millennium when called with no parameters, change the current month when called with an integer value + * @method int|static monthOfQuarter(?int $month = null) Return the value of the month starting from the beginning of the current quarter when called with no parameters, change the current month when called with an integer value + * @method int|static monthOfYear(?int $month = null) Return the value of the month starting from the beginning of the current year when called with no parameters, change the current month when called with an integer value + * @method int monthsInCentury() Return the number of months contained in the current century + * @method int monthsInDecade() Return the number of months contained in the current decade + * @method int monthsInMillennium() Return the number of months contained in the current millennium + * @method int monthsInQuarter() Return the number of months contained in the current quarter + * @method int monthsInYear() Return the number of months contained in the current year + * @method int|static quarterOfCentury(?int $quarter = null) Return the value of the quarter starting from the beginning of the current century when called with no parameters, change the current quarter when called with an integer value + * @method int|static quarterOfDecade(?int $quarter = null) Return the value of the quarter starting from the beginning of the current decade when called with no parameters, change the current quarter when called with an integer value + * @method int|static quarterOfMillennium(?int $quarter = null) Return the value of the quarter starting from the beginning of the current millennium when called with no parameters, change the current quarter when called with an integer value + * @method int|static quarterOfYear(?int $quarter = null) Return the value of the quarter starting from the beginning of the current year when called with no parameters, change the current quarter when called with an integer value + * @method int quartersInCentury() Return the number of quarters contained in the current century + * @method int quartersInDecade() Return the number of quarters contained in the current decade + * @method int quartersInMillennium() Return the number of quarters contained in the current millennium + * @method int quartersInYear() Return the number of quarters contained in the current year + * @method int|static secondOfCentury(?int $second = null) Return the value of the second starting from the beginning of the current century when called with no parameters, change the current second when called with an integer value + * @method int|static secondOfDay(?int $second = null) Return the value of the second starting from the beginning of the current day when called with no parameters, change the current second when called with an integer value + * @method int|static secondOfDecade(?int $second = null) Return the value of the second starting from the beginning of the current decade when called with no parameters, change the current second when called with an integer value + * @method int|static secondOfHour(?int $second = null) Return the value of the second starting from the beginning of the current hour when called with no parameters, change the current second when called with an integer value + * @method int|static secondOfMillennium(?int $second = null) Return the value of the second starting from the beginning of the current millennium when called with no parameters, change the current second when called with an integer value + * @method int|static secondOfMinute(?int $second = null) Return the value of the second starting from the beginning of the current minute when called with no parameters, change the current second when called with an integer value + * @method int|static secondOfMonth(?int $second = null) Return the value of the second starting from the beginning of the current month when called with no parameters, change the current second when called with an integer value + * @method int|static secondOfQuarter(?int $second = null) Return the value of the second starting from the beginning of the current quarter when called with no parameters, change the current second when called with an integer value + * @method int|static secondOfWeek(?int $second = null) Return the value of the second starting from the beginning of the current week when called with no parameters, change the current second when called with an integer value + * @method int|static secondOfYear(?int $second = null) Return the value of the second starting from the beginning of the current year when called with no parameters, change the current second when called with an integer value + * @method int secondsInCentury() Return the number of seconds contained in the current century + * @method int secondsInDay() Return the number of seconds contained in the current day + * @method int secondsInDecade() Return the number of seconds contained in the current decade + * @method int secondsInHour() Return the number of seconds contained in the current hour + * @method int secondsInMillennium() Return the number of seconds contained in the current millennium + * @method int secondsInMinute() Return the number of seconds contained in the current minute + * @method int secondsInMonth() Return the number of seconds contained in the current month + * @method int secondsInQuarter() Return the number of seconds contained in the current quarter + * @method int secondsInWeek() Return the number of seconds contained in the current week + * @method int secondsInYear() Return the number of seconds contained in the current year + * @method int|static weekOfCentury(?int $week = null) Return the value of the week starting from the beginning of the current century when called with no parameters, change the current week when called with an integer value + * @method int|static weekOfDecade(?int $week = null) Return the value of the week starting from the beginning of the current decade when called with no parameters, change the current week when called with an integer value + * @method int|static weekOfMillennium(?int $week = null) Return the value of the week starting from the beginning of the current millennium when called with no parameters, change the current week when called with an integer value + * @method int|static weekOfMonth(?int $week = null) Return the value of the week starting from the beginning of the current month when called with no parameters, change the current week when called with an integer value + * @method int|static weekOfQuarter(?int $week = null) Return the value of the week starting from the beginning of the current quarter when called with no parameters, change the current week when called with an integer value + * @method int|static weekOfYear(?int $week = null) Return the value of the week starting from the beginning of the current year when called with no parameters, change the current week when called with an integer value + * @method int weeksInCentury() Return the number of weeks contained in the current century + * @method int weeksInDecade() Return the number of weeks contained in the current decade + * @method int weeksInMillennium() Return the number of weeks contained in the current millennium + * @method int weeksInMonth() Return the number of weeks contained in the current month + * @method int weeksInQuarter() Return the number of weeks contained in the current quarter + * @method int|static yearOfCentury(?int $year = null) Return the value of the year starting from the beginning of the current century when called with no parameters, change the current year when called with an integer value + * @method int|static yearOfDecade(?int $year = null) Return the value of the year starting from the beginning of the current decade when called with no parameters, change the current year when called with an integer value + * @method int|static yearOfMillennium(?int $year = null) Return the value of the year starting from the beginning of the current millennium when called with no parameters, change the current year when called with an integer value + * @method int yearsInCentury() Return the number of years contained in the current century + * @method int yearsInDecade() Return the number of years contained in the current decade + * @method int yearsInMillennium() Return the number of years contained in the current millennium + * @method static plus(int $years = 0, int $months = 0, int|float $weeks = 0, int|float $days = 0, int|float $hours = 0, int|float $minutes = 0, int|float $seconds = 0, int|float $microseconds = 0, OverflowMode|bool|null $overflow = null, ?int $anchorDay = null) Add given amount of time to the current date. + * @method static minus(int $years = 0, int $months = 0, int|float $weeks = 0, int|float $days = 0, int|float $hours = 0, int|float $minutes = 0, int|float $seconds = 0, int|float $microseconds = 0, OverflowMode|bool|null $overflow = null, ?int $anchorDay = null) Subtract given amount of time to the current date. + * + * + */ +class CarbonImmutable extends DateTimeImmutable implements CarbonInterface +{ + use Date { + __clone as dateTraitClone; + } + + public function __clone(): void + { + $this->dateTraitClone(); + $this->endOfTime = false; + $this->startOfTime = false; + } + + /** + * Create a very old date representing start of time. + * + * @return static + */ + public static function startOfTime(): static + { + $date = static::parse('0001-01-01')->years(self::getStartOfTimeYear()); + $date->startOfTime = true; + + return $date; + } + + /** + * Create a very far date representing end of time. + * + * @return static + */ + public static function endOfTime(): static + { + $date = static::parse('9999-12-31 23:59:59.999999')->years(self::getEndOfTimeYear()); + $date->endOfTime = true; + + return $date; + } + + /** + * @codeCoverageIgnore + */ + private static function getEndOfTimeYear(): int + { + return 1118290769066902787; // PHP_INT_MAX no longer work since PHP 8.1 + } + + /** + * @codeCoverageIgnore + */ + private static function getStartOfTimeYear(): int + { + return -1118290769066898816; // PHP_INT_MIN no longer work since PHP 8.1 + } +} diff --git a/tests/CarbonImmutable/DiffTest.php b/tests/CarbonImmutable/DiffTest.php new file mode 100644 index 0000000..6a24275 --- /dev/null +++ b/tests/CarbonImmutable/DiffTest.php @@ -0,0 +1,1964 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Tests\CarbonImmutable; + +use Carbon\CarbonImmutable as Carbon; +use Carbon\CarbonInterface; +use Carbon\CarbonInterval; +use Carbon\Exceptions\InvalidFormatException; +use Carbon\Exceptions\UnknownUnitException; +use Closure; +use DateTime; +use Tests\AbstractTestCase; +use TypeError; + +class DiffTest extends AbstractTestCase +{ + public function wrapWithTestNow(Closure $func, ?CarbonInterface $dt = null): void + { + parent::wrapWithTestNow($func, $dt ?: Carbon::createMidnightDate(2012, 1, 1)); + } + + public function testDiffAsCarbonInterval() + { + $dt = Carbon::createFromDate(2000, 1, 1); + $this->assertCarbonInterval($dt->diff($dt->copy()->addYear()), 1, 0, 0, 0, 0, 0); + $this->assertTrue($dt->diff($dt)->isEmpty()); + } + + public function testDiffInYearsPositive() + { + $dt = Carbon::createFromDate(2000, 1, 1); + $this->assertSame(1.0, $dt->diffInYears($dt->copy()->addYear())); + } + + public function testDiffInYearsNegativeWithSign() + { + $dt = Carbon::createFromDate(2000, 1, 1); + $this->assertSame(-1.0, $dt->diffInYears($dt->copy()->subYear())); + } + + public function testDiffInYearsNegativeNoSign() + { + $dt = Carbon::createFromDate(2000, 1, 1); + $this->assertSame(1.0, $dt->diffInYears($dt->copy()->subYear(), true)); + } + + public function testDiffInYearsVsDefaultNow() + { + $this->wrapWithTestNow(function () { + $this->assertSame(1.0, Carbon::now()->subYear()->diffInYears()); + }); + } + + public function testDiffInYearsEnsureIsTruncated() + { + $dt = Carbon::createFromDate(2000, 1, 1); + $this->assertSame(1, (int) $dt->diffInYears($dt->copy()->addYear()->addMonths(7))); + } + + public function testDiffInQuartersPositive() + { + $dt = Carbon::createFromDate(2000, 1, 1); + $this->assertSame(1, (int) $dt->diffInQuarters($dt->copy()->addQuarter()->addDay())); + } + + public function testDiffInQuartersNegativeWithSign() + { + $dt = Carbon::createFromDate(2000, 1, 1); + $this->assertSame(-4, (int) $dt->diffInQuarters($dt->copy()->subQuarters(4))); + } + + public function testDiffInQuartersNegativeWithNoSign() + { + $dt = Carbon::createFromDate(2000, 1, 1); + $this->assertSame(4, (int) $dt->diffInQuarters($dt->copy()->subQuarters(4), true)); + } + + public function testDiffInQuartersVsDefaultNow() + { + $this->wrapWithTestNow(function () { + $this->assertSame(4, (int) Carbon::now()->subYear()->diffInQuarters()); + }); + } + + public function testDiffInQuartersEnsureIsTruncated() + { + $dt = Carbon::createFromDate(2000, 1, 1); + $this->assertSame(1, (int) $dt->diffInQuarters($dt->copy()->addQuarter()->addDays(12))); + } + + public function testDiffInMonthsPositive() + { + $dt = Carbon::createFromDate(2000, 1, 1); + $this->assertSame(13, (int) $dt->diffInMonths($dt->copy()->addYear()->addMonth())); + } + + public function testDiffInMonthsNegativeWithSign() + { + $dt = Carbon::createFromDate(2000, 1, 1); + $this->assertSame(-11, (int) $dt->diffInMonths($dt->copy()->subYear()->addMonth())); + } + + public function testDiffInMonthsNegativeNoSign() + { + $dt = Carbon::createFromDate(2000, 1, 1); + $this->assertSame(11, (int) $dt->diffInMonths($dt->copy()->subYear()->addMonth(), true)); + } + + public function testDiffInMonthsVsDefaultNow() + { + $this->wrapWithTestNow(function () { + $this->assertSame(12, (int) Carbon::now()->subYear()->diffInMonths()); + }); + } + + public function testDiffInMonthsEnsureIsTruncated() + { + $dt = Carbon::createFromDate(2000, 1, 1); + $this->assertSame(1, (int) $dt->diffInMonths($dt->copy()->addMonth()->addDays(16))); + } + + public function testDiffInDaysPositive() + { + $dt = Carbon::createFromDate(2000, 1, 1); + $this->assertSame(366.0, $dt->diffInDays($dt->copy()->addYear())); + } + + public function testDiffInDaysNegativeWithSign() + { + $dt = Carbon::createFromDate(2000, 1, 1); + $this->assertSame(-365.0, $dt->diffInDays($dt->copy()->subYear())); + } + + public function testDiffInDaysNegativeNoSign() + { + $dt = Carbon::createFromDate(2000, 1, 1); + $this->assertSame(365.0, $dt->diffInDays($dt->copy()->subYear(), true)); + } + + public function testDiffInDaysVsDefaultNow() + { + $this->wrapWithTestNow(function () { + $this->assertSame(7.0, Carbon::now()->subWeek()->diffInDays()); + }); + } + + public function testDiffInDaysEnsureIsTruncated() + { + $dt = Carbon::createFromDate(2000, 1, 1); + $this->assertSame(1, (int) $dt->diffInDays($dt->copy()->addDay()->addHours(13))); + } + + public function testDiffInDaysFilteredPositiveWithMutated() + { + $dt = Carbon::createFromDate(2000, 1, 1); + $this->assertSame(5, $dt->diffInDaysFiltered(function (Carbon $date) { + return $date->dayOfWeek === 1; + }, $dt->copy()->endOfMonth())); + } + + public function testDiffInDaysFilteredPositiveWithSecondObject() + { + $dt1 = Carbon::createFromDate(2000, 1, 1); + $dt2 = Carbon::createFromDate(2000, 1, 31); + + $this->assertSame(5, $dt1->diffInDaysFiltered(function (Carbon $date) { + return $date->dayOfWeek === Carbon::SUNDAY; + }, $dt2)); + } + + public function testDiffInDaysFilteredNegativeNoSignWithMutated() + { + $dt = Carbon::createFromDate(2000, 1, 31); + $this->assertSame(-5, $dt->diffInDaysFiltered(function (Carbon $date) { + return $date->dayOfWeek === Carbon::SUNDAY; + }, $dt->copy()->startOfMonth())); + } + + public function testDiffInDaysFilteredNegativeNoSignWithSecondObject() + { + $dt1 = Carbon::createFromDate(2000, 1, 31); + $dt2 = Carbon::createFromDate(2000, 1, 1); + + $this->assertSame(5, $dt1->diffInDaysFiltered(function (Carbon $date) { + return $date->dayOfWeek === Carbon::SUNDAY; + }, $dt2, true)); + } + + public function testDiffInDaysFilteredNegativeWithSignWithMutated() + { + $dt = Carbon::createFromDate(2000, 1, 31); + $this->assertSame(-5, $dt->diffInDaysFiltered(function (Carbon $date) { + return $date->dayOfWeek === 1; + }, $dt->copy()->startOfMonth())); + } + + public function testDiffInDaysFilteredNegativeWithSignWithSecondObject() + { + $dt1 = Carbon::createFromDate(2000, 1, 31); + $dt2 = Carbon::createFromDate(2000, 1, 1); + + $this->assertSame(-5, $dt1->diffInDaysFiltered(function (Carbon $date) { + return $date->dayOfWeek === Carbon::SUNDAY; + }, $dt2)); + } + + public function testDiffInHoursFiltered() + { + $dt1 = Carbon::createFromDate(2000, 1, 31)->endOfDay(); + $dt2 = Carbon::createFromDate(2000, 1, 1)->startOfDay(); + + $this->assertSame(-31, $dt1->diffInHoursFiltered(function (Carbon $date) { + return $date->hour === 9; + }, $dt2)); + } + + public function testDiffInHoursFilteredNegative() + { + $dt1 = Carbon::createFromDate(2000, 1, 31)->endOfDay(); + $dt2 = Carbon::createFromDate(2000, 1, 1)->startOfDay(); + + $this->assertSame(-31, $dt1->diffInHoursFiltered(function (Carbon $date) { + return $date->hour === 9; + }, $dt2)); + } + + public function testDiffInHoursFilteredWorkHoursPerWeek() + { + $dt1 = Carbon::createFromDate(2000, 1, 5)->endOfDay(); + $dt2 = Carbon::createFromDate(2000, 1, 1)->startOfDay(); + + $this->assertSame(-40, $dt1->diffInHoursFiltered(function (Carbon $date) { + return $date->hour > 8 && $date->hour < 17; + }, $dt2)); + } + + public function testDiffFilteredUsingMinutesPositiveWithMutated() + { + $dt = Carbon::createFromDate(2000, 1, 1)->startOfDay(); + $this->assertSame(60, $dt->diffFiltered(CarbonInterval::minute(), function (Carbon $date) { + return $date->hour === 12; + }, Carbon::createFromDate(2000, 1, 1)->endOfDay())); + } + + public function testDiffFilteredPositiveWithSecondObject() + { + $dt1 = Carbon::create(2000, 1, 1); + $dt2 = $dt1->copy()->addSeconds(80); + + $this->assertSame(40, $dt1->diffFiltered(CarbonInterval::second(), function (Carbon $date) { + return $date->second % 2 === 0; + }, $dt2)); + } + + public function testDiffFilteredNegativeNoSignWithMutated() + { + $dt = Carbon::createFromDate(2000, 1, 31); + + $this->assertSame(-2, $dt->diffFiltered(CarbonInterval::days(2), function (Carbon $date) { + return $date->dayOfWeek === Carbon::SUNDAY; + }, $dt->copy()->startOfMonth())); + } + + public function testDiffFilteredNegativeNoSignWithSecondObject() + { + $dt1 = Carbon::createFromDate(2006, 1, 31); + $dt2 = Carbon::createFromDate(2000, 1, 1); + + $this->assertSame(-7, $dt1->diffFiltered(CarbonInterval::year(), function (Carbon $date) { + return $date->month === 1; + }, $dt2)); + } + + public function testDiffFilteredNegativeWithSignWithMutated() + { + $dt = Carbon::createFromDate(2000, 1, 31); + $this->assertSame(-4, $dt->diffFiltered(CarbonInterval::week(), function (Carbon $date) { + return $date->month === 12; + }, $dt->copy()->subMonths(3), false)); + } + + public function testDiffFilteredNegativeWithSignWithSecondObject() + { + $dt1 = Carbon::createFromDate(2001, 1, 31); + $dt2 = Carbon::createFromDate(1999, 1, 1); + + $this->assertSame(-12, $dt1->diffFiltered(CarbonInterval::month(), function (Carbon $date) { + return $date->year === 2000; + }, $dt2, false)); + } + + public function testBug188DiffWithSameDates() + { + $start = Carbon::create(2014, 10, 8, 15, 20, 0); + $end = $start->copy(); + + $this->assertSame(0.0, $start->diffInDays($end)); + $this->assertSame(0, $start->diffInWeekdays($end)); + } + + public function testBug188DiffWithDatesOnlyHoursApart() + { + $start = Carbon::create(2014, 10, 8, 15, 20, 0); + $end = $start->copy(); + + $this->assertSame(0.0, $start->diffInDays($end)); + $this->assertSame(0, $start->diffInWeekdays($end)); + } + + public function testBug188DiffWithSameDates1DayApart() + { + $start = Carbon::create(2014, 10, 8, 15, 20, 0); + $end = $start->copy()->addDay(); + + $this->assertSame(1.0, $start->diffInDays($end)); + $this->assertSame(1, $start->diffInWeekdays($end)); + } + + public function testBug188DiffWithDatesOnTheWeekend() + { + $start = Carbon::create(2014, 1, 1, 0, 0, 0); + $start = $start->next(Carbon::SATURDAY); + $end = $start->copy()->addDay(); + + $this->assertSame(1.0, $start->diffInDays($end)); + $this->assertSame(0, $start->diffInWeekdays($end)); + } + + public function testDiffInWeekdaysPositive() + { + $dt = Carbon::createFromDate(2000, 1, 1); + $this->assertSame(21, $dt->diffInWeekdays($dt->copy()->addMonth())); + } + + public function testDiffInWeekdaysNegativeNoSign() + { + $dt = Carbon::createFromDate(2000, 1, 31); + $this->assertSame(20, $dt->diffInWeekdays($dt->copy()->startOfMonth(), true)); + } + + public function testDiffInWeekdaysNegativeWithSign() + { + $dt = Carbon::createFromDate(2000, 1, 31); + $this->assertSame(-20, $dt->diffInWeekdays($dt->copy()->startOfMonth())); + } + + public function testDiffInWeekendDaysPositive() + { + $dt = Carbon::createFromDate(2000, 1, 1); + $this->assertSame(10, $dt->diffInWeekendDays($dt->copy()->endOfMonth())); + } + + public function testDiffInWeekendDaysNegativeNoSign() + { + $dt = Carbon::createFromDate(2000, 1, 31); + $this->assertSame(10, $dt->diffInWeekendDays($dt->copy()->startOfMonth(), true)); + } + + public function testDiffInWeekendDaysNegativeWithSign() + { + $dt = Carbon::createFromDate(2000, 1, 31); + $this->assertSame(-10, $dt->diffInWeekendDays($dt->copy()->startOfMonth())); + } + + public function testDiffInWeeksPositive() + { + $dt = Carbon::createFromDate(2000, 1, 1); + $this->assertSame(52, (int) $dt->diffInWeeks($dt->copy()->addYear())); + } + + public function testDiffInWeeksNegativeWithSign() + { + $dt = Carbon::createFromDate(2000, 1, 1); + $this->assertSame(-52, (int) $dt->diffInWeeks($dt->copy()->subYear())); + } + + public function testDiffInWeeksNegativeNoSign() + { + $dt = Carbon::createFromDate(2000, 1, 1); + $this->assertSame(52, (int) $dt->diffInWeeks($dt->copy()->subYear(), true)); + } + + public function testDiffInWeeksVsDefaultNow() + { + $this->wrapWithTestNow(function () { + $this->assertSame(1.0, Carbon::now()->subWeek()->diffInWeeks()); + }); + } + + public function testDiffInWeeksEnsureIsTruncated() + { + $dt = Carbon::createFromDate(2000, 1, 1); + $this->assertSame(0.86, round($dt->diffInWeeks($dt->copy()->addWeek()->subDay()), 2)); + } + + public function testDiffInHoursPositive() + { + $dt = Carbon::createFromDate(2000, 1, 1); + $this->assertSame(26.0, $dt->diffInHours($dt->copy()->addDay()->addHours(2))); + } + + public function testDiffInHoursNegativeWithSign() + { + $dt = Carbon::createFromDate(2000, 1, 1); + $this->assertSame(-22.0, $dt->diffInHours($dt->copy()->subDay()->addHours(2))); + } + + public function testDiffInHoursNegativeNoSign() + { + $dt = Carbon::createFromDate(2000, 1, 1); + $this->assertSame(22.0, $dt->diffInHours($dt->copy()->subDay()->addHours(2), true)); + } + + public function testDiffInHoursVsDefaultNow() + { + $this->wrapWithTestNow(function () { + $this->assertSame(48.0, Carbon::now()->subDays(2)->diffInHours()); + }, Carbon::create(2012, 1, 15)); + } + + public function testDiffInHoursEnsureIsTruncated() + { + $dt = Carbon::createFromDate(2000, 1, 1); + $this->assertSame(1.52, round($dt->diffInHours($dt->copy()->addHour()->addMinutes(31)), 2)); + } + + public function testDiffInHoursWithTimezones() + { + date_default_timezone_set('Africa/Algiers'); + Carbon::setTestNow(); + + $dtToronto = Carbon::create(2012, 1, 1, 0, 0, 0, 'America/Toronto'); + $dtVancouver = Carbon::create(2012, 1, 1, 0, 0, 0, 'America/Vancouver'); + + $this->assertSame(-3.0, $dtVancouver->diffInHours($dtToronto), 'Midnight in Toronto is 3 hours from midnight in Vancouver'); + + $dtToronto = Carbon::createFromDate(2012, 1, 1, 'America/Toronto'); + usleep(2); + $dtVancouver = Carbon::createFromDate(2012, 1, 1, 'America/Vancouver'); + + $this->assertSame(0, ((int) round($dtVancouver->diffInHours($dtToronto))) % 24); + + $dtToronto = Carbon::createMidnightDate(2012, 1, 1, 'America/Toronto'); + $dtVancouver = Carbon::createMidnightDate(2012, 1, 1, 'America/Vancouver'); + + $this->assertSame(-3.0, $dtVancouver->diffInHours($dtToronto), 'Midnight in Toronto is 3 hours from midnight in Vancouver'); + } + + public function testDiffInMinutesPositive() + { + $dt = Carbon::createFromDate(2000, 1, 1); + $this->assertSame(62.0, $dt->diffInMinutes($dt->copy()->addHour()->addMinutes(2))); + } + + public function testDiffInMinutesPositiveALot() + { + $dt = Carbon::createFromDate(2000, 1, 1); + $this->assertSame(1502.0, $dt->diffInMinutes($dt->copy()->addHours(25)->addMinutes(2))); + } + + public function testDiffInMinutesNegativeWithSign() + { + $dt = Carbon::createFromDate(2000, 1, 1); + $this->assertSame(-58.0, $dt->diffInMinutes($dt->copy()->subHour()->addMinutes(2))); + } + + public function testDiffInMinutesNegativeNoSign() + { + $dt = Carbon::createFromDate(2000, 1, 1); + $this->assertSame(58.0, $dt->diffInMinutes($dt->copy()->subHour()->addMinutes(2), true)); + } + + public function testDiffInMinutesVsDefaultNow() + { + $this->wrapWithTestNow(function () { + $this->assertSame(60.0, Carbon::now()->subHour()->diffInMinutes()); + }); + } + + public function testDiffInMinutesEnsureIsTruncated() + { + $dt = Carbon::createFromDate(2000, 1, 1); + $this->assertSame(1.52, round($dt->diffInMinutes($dt->copy()->addMinute()->addSeconds(31)), 2)); + } + + public function testDiffInSecondsPositive() + { + $dt = Carbon::createFromDate(2000, 1, 1); + $this->assertSame(62.0, $dt->diffInSeconds($dt->copy()->addMinute()->addSeconds(2))); + } + + public function testDiffInSecondsPositiveALot() + { + $dt = Carbon::createFromDate(2000, 1, 1); + $this->assertSame(7202.0, $dt->diffInSeconds($dt->copy()->addHours(2)->addSeconds(2))); + } + + public function testDiffInSecondsNegativeWithSign() + { + $dt = Carbon::createFromDate(2000, 1, 1); + $this->assertSame(-58.0, $dt->diffInSeconds($dt->copy()->subMinute()->addSeconds(2))); + } + + public function testDiffInSecondsNegativeNoSign() + { + $dt = Carbon::createFromDate(2000, 1, 1); + $this->assertSame(58.0, $dt->diffInSeconds($dt->copy()->subMinute()->addSeconds(2), true)); + } + + public function testDiffInSecondsVsDefaultNow() + { + $this->wrapWithTestNow(function () { + $this->assertSame(3600.0, Carbon::now()->subHour()->diffInSeconds()); + }); + } + + public function testDiffInSecondsEnsureIsTruncated() + { + $dt = Carbon::createFromDate(2000, 1, 1); + $this->assertSame(1.0, $dt->diffInSeconds($dt->copy()->addSeconds((int) 1.9))); + } + + public function testDiffInSecondsWithTimezones() + { + $dtOttawa = Carbon::createFromDate(2000, 1, 1, 'America/Toronto'); + $dtVancouver = Carbon::createFromDate(2000, 1, 1, 'America/Vancouver'); + $this->assertSame(0, $dtOttawa->diffInSeconds($dtVancouver) % (24 * 3600)); + + $dtOttawa = Carbon::createMidnightDate(2000, 1, 1, 'America/Toronto'); + $dtVancouver = Carbon::createMidnightDate(2000, 1, 1, 'America/Vancouver'); + $this->assertSame(3.0 * 60 * 60, $dtOttawa->diffInSeconds($dtVancouver)); + } + + public function testDiffInSecondsWithTimezonesAndVsDefault() + { + $vanNow = Carbon::now('America/Vancouver'); + $hereNow = $vanNow->copy()->setTimezone(Carbon::now()->tz); + $this->wrapWithTestNow(function () use ($vanNow) { + $this->assertSame(0.0, $vanNow->diffInSeconds()); + }, $hereNow); + } + + public function testDiffForHumansNowAndSecond() + { + $this->wrapWithTestNow(function () { + $this->assertSame('0 seconds ago', Carbon::now()->diffForHumans()); + }); + } + + /** + * @see https://github.com/briannesbitt/Carbon/issues/2136 + */ + public function testDiffInTheFuture() + { + Carbon::setTestNow('2020-07-22 09:15'); + + $this->assertSame( + '1 week from now', + Carbon::parse('2020-07-30 13:51:15') + ->diffForHumans(['options' => CarbonInterface::ROUND]), + ); + } + + public function testDiffForHumansNowAndSecondWithTimezone() + { + $vanNow = Carbon::now('America/Vancouver'); + $hereNow = $vanNow->copy()->setTimezone(Carbon::now()->tz); + $this->wrapWithTestNow(function () use ($vanNow) { + $this->assertSame('0 seconds ago', $vanNow->diffForHumans()); + }, $hereNow); + } + + public function testDiffForHumansNowAndSeconds() + { + $this->wrapWithTestNow(function () { + $this->assertSame('2 seconds ago', Carbon::now()->subSeconds(2)->diffForHumans()); + }); + } + + public function testDiffForHumansNowAndNearlyMinute() + { + $this->wrapWithTestNow(function () { + $this->assertSame('59 seconds ago', Carbon::now()->subSeconds(59)->diffForHumans()); + }); + } + + public function testDiffForHumansNowAndMinute() + { + $this->wrapWithTestNow(function () { + $this->assertSame('1 minute ago', Carbon::now()->subMinute()->diffForHumans()); + }); + } + + public function testDiffForHumansNowAndMinutes() + { + $this->wrapWithTestNow(function () { + $this->assertSame('2 minutes ago', Carbon::now()->subMinutes(2)->diffForHumans()); + }); + } + + public function testDiffForHumansNowAndNearlyHour() + { + $this->wrapWithTestNow(function () { + $this->assertSame('59 minutes ago', Carbon::now()->subMinutes(59)->diffForHumans()); + }); + } + + public function testDiffForHumansNowAndHour() + { + $this->wrapWithTestNow(function () { + $this->assertSame('1 hour ago', Carbon::now()->subHour()->diffForHumans()); + }); + } + + public function testDiffForHumansNowAndHours() + { + $this->wrapWithTestNow(function () { + $this->assertSame('2 hours ago', Carbon::now()->subHours(2)->diffForHumans()); + }); + } + + public function testDiffForHumansNowAndNearlyDay() + { + $this->wrapWithTestNow(function () { + $this->assertSame('23 hours ago', Carbon::now()->subHours(23)->diffForHumans()); + }); + } + + public function testDiffForHumansNowAndDay() + { + $this->wrapWithTestNow(function () { + $this->assertSame('1 day ago', Carbon::now()->subDay()->diffForHumans()); + }); + } + + public function testDiffForHumansNowAndDays() + { + $this->wrapWithTestNow(function () { + $this->assertSame('2 days ago', Carbon::now()->subDays(2)->diffForHumans()); + }); + } + + public function testDiffForHumansNowAndNearlyWeek() + { + $this->wrapWithTestNow(function () { + $this->assertSame('6 days ago', Carbon::now()->subDays(6)->diffForHumans()); + }); + } + + public function testDiffForHumansNowAndWeek() + { + $this->wrapWithTestNow(function () { + $this->assertSame('1 week ago', Carbon::now()->subWeek()->diffForHumans()); + }); + } + + public function testDiffForHumansNowAndWeeks() + { + $this->wrapWithTestNow(function () { + $this->assertSame('2 weeks ago', Carbon::now()->subWeeks(2)->diffForHumans()); + }); + } + + public function testDiffForHumansNowAndNearlyMonth() + { + $this->wrapWithTestNow(function () { + $this->assertSame('3 weeks ago', Carbon::now()->subWeeks(3)->diffForHumans()); + }); + } + + public function testDiffForHumansNowAndMonth() + { + Carbon::setTestNow('2018-12-01'); + $this->assertSame('4 weeks ago', Carbon::now()->subWeeks(4)->diffForHumans()); + $this->assertSame('1 month ago', Carbon::now()->subMonth()->diffForHumans()); + } + + public function testDiffForHumansNowAndMonths() + { + $this->wrapWithTestNow(function () { + $this->assertSame('2 months ago', Carbon::now()->subMonthsNoOverflow(2)->diffForHumans()); + }); + } + + public function testDiffForHumansNowAndNearlyYear() + { + $this->wrapWithTestNow(function () { + $this->assertSame('11 months ago', Carbon::now()->subMonthsNoOverflow(11)->diffForHumans()); + }); + } + + public function testDiffForHumansNowAndYear() + { + $this->wrapWithTestNow(function () { + $this->assertSame('1 year ago', Carbon::now()->subYear()->diffForHumans()); + }); + } + + public function testDiffForHumansNowAndYears() + { + $this->wrapWithTestNow(function () { + $this->assertSame('2 years ago', Carbon::now()->subYears(2)->diffForHumans()); + }); + } + + public function testDiffForHumansNowAndFutureSecond() + { + $this->wrapWithTestNow(function () { + $this->assertSame('1 second from now', Carbon::now()->addSecond()->diffForHumans()); + }); + } + + public function testDiffForHumansNowAndFutureSeconds() + { + $this->wrapWithTestNow(function () { + $this->assertSame('2 seconds from now', Carbon::now()->addSeconds(2)->diffForHumans()); + }); + } + + public function testDiffForHumansNowAndNearlyFutureMinute() + { + $this->wrapWithTestNow(function () { + $this->assertSame('59 seconds from now', Carbon::now()->addSeconds(59)->diffForHumans()); + }); + } + + public function testDiffForHumansNowAndFutureMinute() + { + $this->wrapWithTestNow(function () { + $this->assertSame('1 minute from now', Carbon::now()->addMinute()->diffForHumans()); + }); + } + + public function testDiffForHumansNowAndFutureMinutes() + { + $this->wrapWithTestNow(function () { + $this->assertSame('2 minutes from now', Carbon::now()->addMinutes(2)->diffForHumans()); + }); + } + + public function testDiffForHumansNowAndNearlyFutureHour() + { + $this->wrapWithTestNow(function () { + $this->assertSame('59 minutes from now', Carbon::now()->addMinutes(59)->diffForHumans()); + }); + } + + public function testDiffForHumansNowAndFutureHour() + { + $this->wrapWithTestNow(function () { + $this->assertSame('1 hour from now', Carbon::now()->addHour()->diffForHumans()); + }); + } + + public function testDiffForHumansNowAndFutureHours() + { + $this->wrapWithTestNow(function () { + $this->assertSame('2 hours from now', Carbon::now()->addHours(2)->diffForHumans()); + }); + } + + public function testDiffForHumansNowAndNearlyFutureDay() + { + $this->wrapWithTestNow(function () { + $this->assertSame('23 hours from now', Carbon::now()->addHours(23)->diffForHumans()); + }); + } + + public function testDiffForHumansNowAndFutureDay() + { + $this->wrapWithTestNow(function () { + $this->assertSame('1 day from now', Carbon::now()->addDay()->diffForHumans()); + }); + } + + public function testDiffForHumansNowAndFutureDays() + { + $this->wrapWithTestNow(function () { + $this->assertSame('2 days from now', Carbon::now()->addDays(2)->diffForHumans()); + }); + } + + public function testDiffForHumansNowAndNearlyFutureWeek() + { + $this->wrapWithTestNow(function () { + $this->assertSame('6 days from now', Carbon::now()->addDays(6)->diffForHumans()); + }); + } + + public function testDiffForHumansNowAndFutureWeek() + { + $this->wrapWithTestNow(function () { + $this->assertSame('1 week from now', Carbon::now()->addWeek()->diffForHumans()); + }); + } + + public function testDiffForHumansNowAndFutureWeeks() + { + $this->wrapWithTestNow(function () { + $this->assertSame('2 weeks from now', Carbon::now()->addWeeks(2)->diffForHumans()); + }); + } + + public function testDiffForHumansNowAndNearlyFutureMonth() + { + $this->wrapWithTestNow(function () { + $this->assertSame('3 weeks from now', Carbon::now()->addWeeks(3)->diffForHumans()); + }); + } + + public function testDiffForHumansNowAndFutureMonth() + { + $this->wrapWithTestNow(function () { + $this->assertSame('4 weeks from now', Carbon::now()->addWeeks(4)->diffForHumans()); + $this->assertSame('1 month from now', Carbon::now()->addMonth()->diffForHumans()); + }); + } + + public function testDiffForHumansNowAndFutureMonths() + { + $this->wrapWithTestNow(function () { + $this->assertSame('2 months from now', Carbon::now()->addMonths(2)->diffForHumans()); + }); + } + + public function testDiffForHumansNowAndNearlyFutureYear() + { + $this->wrapWithTestNow(function () { + $this->assertSame('11 months from now', Carbon::now()->addMonths(11)->diffForHumans()); + }); + } + + public function testDiffForHumansNowAndFutureYear() + { + $this->wrapWithTestNow(function () { + $this->assertSame('1 year from now', Carbon::now()->addYear()->diffForHumans()); + }); + } + + public function testDiffForHumansNowAndFutureYears() + { + $this->wrapWithTestNow(function () { + $this->assertSame('2 years from now', Carbon::now()->addYears(2)->diffForHumans()); + }); + } + + public function testDiffForHumansOtherAndSecond() + { + $this->wrapWithTestNow(function () { + $this->assertSame('1 second before', Carbon::now()->diffForHumans(Carbon::now()->addSecond())); + }); + } + + public function testDiffForHumansOtherAndSeconds() + { + $this->wrapWithTestNow(function () { + $this->assertSame('2 seconds before', Carbon::now()->diffForHumans(Carbon::now()->addSeconds(2))); + }); + } + + public function testDiffForHumansOtherAndNearlyMinute() + { + $this->wrapWithTestNow(function () { + $this->assertSame('59 seconds before', Carbon::now()->diffForHumans(Carbon::now()->addSeconds(59))); + }); + } + + public function testDiffForHumansOtherAndMinute() + { + $this->wrapWithTestNow(function () { + $this->assertSame('1 minute before', Carbon::now()->diffForHumans(Carbon::now()->addMinute())); + }); + } + + public function testDiffForHumansOtherAndMinutes() + { + $this->wrapWithTestNow(function () { + $this->assertSame('2 minutes before', Carbon::now()->diffForHumans(Carbon::now()->addMinutes(2))); + }); + } + + public function testDiffForHumansOtherAndNearlyHour() + { + $this->wrapWithTestNow(function () { + $this->assertSame('59 minutes before', Carbon::now()->diffForHumans(Carbon::now()->addMinutes(59))); + }); + } + + public function testDiffForHumansOtherAndHour() + { + $this->wrapWithTestNow(function () { + $this->assertSame('1 hour before', Carbon::now()->diffForHumans(Carbon::now()->addHour())); + }); + } + + public function testDiffForHumansOtherAndHours() + { + $this->wrapWithTestNow(function () { + $this->assertSame('2 hours before', Carbon::now()->diffForHumans(Carbon::now()->addHours(2))); + }); + } + + public function testDiffForHumansOtherAndNearlyDay() + { + $this->wrapWithTestNow(function () { + $this->assertSame('23 hours before', Carbon::now()->diffForHumans(Carbon::now()->addHours(23))); + }); + } + + public function testDiffForHumansOtherAndDay() + { + $this->wrapWithTestNow(function () { + $this->assertSame('1 day before', Carbon::now()->diffForHumans(Carbon::now()->addDay())); + }); + } + + public function testDiffForHumansOtherAndDays() + { + $this->wrapWithTestNow(function () { + $this->assertSame('2 days before', Carbon::now()->diffForHumans(Carbon::now()->addDays(2))); + }); + } + + public function testDiffForHumansOtherAndNearlyWeek() + { + $this->wrapWithTestNow(function () { + $this->assertSame('6 days before', Carbon::now()->diffForHumans(Carbon::now()->addDays(6))); + }); + } + + public function testDiffForHumansOverWeekWithDefaultPartsCount() + { + $this->wrapWithTestNow(function () { + $this->assertSame('1 week ago', Carbon::now()->subDays(8)->diffForHumans()); + }); + } + + public function testDiffForHumansOverWeekWithPartsCount1() + { + $this->wrapWithTestNow(function () { + $this->assertSame( + '1 week ago', + Carbon::now()->subDays(8)->diffForHumans(null, false, false, 1) + ); + }); + } + + public function testDiffForHumansOverWeekWithPartsCount2() + { + $this->wrapWithTestNow(function () { + $this->assertSame( + '1 week 1 day ago', + Carbon::now()->subDays(8)->diffForHumans(null, false, false, 2) + ); + }); + } + + public function testDiffForHumansOverWeekWithMicrosecondsBuggyGap() + { + $this->wrapWithTestNow(function () { + $this->assertSame( + '23 hours 59 minutes 59 seconds after', + Carbon::parse('2018-12-03 12:34:45.123456') + ->diffForHumans('2018-12-02 12:34:45.123476', ['parts' => 3]) + ); + }); + } + + public function testDiffForHumansOtherAndWeek() + { + $this->wrapWithTestNow(function () { + $this->assertSame('1 week before', Carbon::now()->diffForHumans(Carbon::now()->addWeek())); + }); + } + + public function testDiffForHumansOtherAndWeeks() + { + $this->wrapWithTestNow(function () { + $this->assertSame('2 weeks before', Carbon::now()->diffForHumans(Carbon::now()->addWeeks(2))); + }); + } + + public function testDiffForHumansOtherAndNearlyMonth() + { + $this->wrapWithTestNow(function () { + $this->assertSame('3 weeks before', Carbon::now()->diffForHumans(Carbon::now()->addWeeks(3))); + }); + } + + public function testDiffForHumansOtherAndMonth() + { + $this->wrapWithTestNow(function () { + $this->assertSame('4 weeks before', Carbon::now()->diffForHumans(Carbon::now()->addWeeks(4))); + $this->assertSame('1 month before', Carbon::now()->diffForHumans(Carbon::now()->addMonth())); + }); + } + + public function testDiffForHumansOtherAndMonths() + { + $this->wrapWithTestNow(function () { + $this->assertSame('2 months before', Carbon::now()->diffForHumans(Carbon::now()->addMonths(2))); + }); + } + + public function testDiffForHumansOtherAndNearlyYear() + { + $this->wrapWithTestNow(function () { + $this->assertSame('11 months before', Carbon::now()->diffForHumans(Carbon::now()->addMonths(11))); + }); + } + + public function testDiffForHumansOtherAndYear() + { + $this->wrapWithTestNow(function () { + $this->assertSame('1 year before', Carbon::now()->diffForHumans(Carbon::now()->addYear())); + }); + } + + public function testDiffForHumansOtherAndYears() + { + $this->wrapWithTestNow(function () { + $this->assertSame('2 years before', Carbon::now()->diffForHumans(Carbon::now()->addYears(2))); + }); + } + + public function testDiffForHumansOtherAndFutureSecond() + { + $this->wrapWithTestNow(function () { + $this->assertSame('1 second after', Carbon::now()->diffForHumans(Carbon::now()->subSecond())); + }); + } + + public function testDiffForHumansOtherAndFutureSeconds() + { + $this->wrapWithTestNow(function () { + $this->assertSame('2 seconds after', Carbon::now()->diffForHumans(Carbon::now()->subSeconds(2))); + }); + } + + public function testDiffForHumansOtherAndNearlyFutureMinute() + { + $this->wrapWithTestNow(function () { + $this->assertSame('59 seconds after', Carbon::now()->diffForHumans(Carbon::now()->subSeconds(59))); + }); + } + + public function testDiffForHumansOtherAndFutureMinute() + { + $this->wrapWithTestNow(function () { + $this->assertSame('1 minute after', Carbon::now()->diffForHumans(Carbon::now()->subMinute())); + }); + } + + public function testDiffForHumansOtherAndFutureMinutes() + { + $this->wrapWithTestNow(function () { + $this->assertSame('2 minutes after', Carbon::now()->diffForHumans(Carbon::now()->subMinutes(2))); + }); + } + + public function testDiffForHumansOtherAndNearlyFutureHour() + { + $this->wrapWithTestNow(function () { + $this->assertSame('59 minutes after', Carbon::now()->diffForHumans(Carbon::now()->subMinutes(59))); + }); + } + + public function testDiffForHumansOtherAndFutureHour() + { + $this->wrapWithTestNow(function () { + $this->assertSame('1 hour after', Carbon::now()->diffForHumans(Carbon::now()->subHour())); + }); + } + + public function testDiffForHumansOtherAndFutureHours() + { + $this->wrapWithTestNow(function () { + $this->assertSame('2 hours after', Carbon::now()->diffForHumans(Carbon::now()->subHours(2))); + }); + } + + public function testDiffForHumansOtherAndNearlyFutureDay() + { + $this->wrapWithTestNow(function () { + $this->assertSame('23 hours after', Carbon::now()->diffForHumans(Carbon::now()->subHours(23))); + }); + } + + public function testDiffForHumansOtherAndFutureDay() + { + $this->wrapWithTestNow(function () { + $this->assertSame('1 day after', Carbon::now()->diffForHumans(Carbon::now()->subDay())); + }); + } + + public function testDiffForHumansOtherAndFutureDays() + { + $this->wrapWithTestNow(function () { + $this->assertSame('2 days after', Carbon::now()->diffForHumans(Carbon::now()->subDays(2))); + }); + } + + public function testDiffForHumansOtherAndNearlyFutureWeek() + { + $this->wrapWithTestNow(function () { + $this->assertSame('6 days after', Carbon::now()->diffForHumans(Carbon::now()->subDays(6))); + }); + } + + public function testDiffForHumansOtherAndFutureWeek() + { + $this->wrapWithTestNow(function () { + $this->assertSame('1 week after', Carbon::now()->diffForHumans(Carbon::now()->subWeek())); + }); + } + + public function testDiffForHumansOtherAndFutureWeeks() + { + $this->wrapWithTestNow(function () { + $this->assertSame('2 weeks after', Carbon::now()->diffForHumans(Carbon::now()->subWeeks(2))); + }); + } + + public function testDiffForHumansOtherAndNearlyFutureMonth() + { + $this->wrapWithTestNow(function () { + $this->assertSame('3 weeks after', Carbon::now()->diffForHumans(Carbon::now()->subWeeks(3))); + }); + } + + public function testDiffForHumansOtherAndFutureMonth() + { + Carbon::setTestNow('2018-12-01'); + $this->assertSame('4 weeks after', Carbon::now()->diffForHumans(Carbon::now()->subWeeks(4))); + $this->assertSame('1 month after', Carbon::now()->diffForHumans(Carbon::now()->subMonth())); + } + + public function testDiffForHumansOtherAndFutureMonths() + { + $this->wrapWithTestNow(function () { + $this->assertSame('2 months after', Carbon::now()->diffForHumans(Carbon::now()->subMonthsNoOverflow(2))); + }); + } + + public function testDiffForHumansOtherAndNearlyFutureYear() + { + $this->wrapWithTestNow(function () { + $this->assertSame('11 months after', Carbon::now()->diffForHumans(Carbon::now()->subMonthsNoOverflow(11))); + }); + } + + public function testDiffForHumansOtherAndFutureYear() + { + $this->wrapWithTestNow(function () { + $this->assertSame('1 year after', Carbon::now()->diffForHumans(Carbon::now()->subYear())); + }); + } + + public function testDiffForHumansOtherAndFutureYears() + { + $this->wrapWithTestNow(function () { + $this->assertSame('2 years after', Carbon::now()->diffForHumans(Carbon::now()->subYears(2))); + }); + } + + public function testDiffForHumansAbsoluteSeconds() + { + $this->wrapWithTestNow(function () { + $this->assertSame('59 seconds', Carbon::now()->diffForHumans(Carbon::now()->subSeconds(59), true)); + $this->assertSame('59 seconds', Carbon::now()->diffForHumans(Carbon::now()->addSeconds(59), true)); + }); + } + + public function testDiffForHumansAbsoluteMinutes() + { + $this->wrapWithTestNow(function () { + $this->assertSame('30 minutes', Carbon::now()->diffForHumans(Carbon::now()->subMinutes(30), true)); + $this->assertSame('30 minutes', Carbon::now()->diffForHumans(Carbon::now()->addMinutes(30), true)); + }); + } + + public function testDiffForHumansAbsoluteHours() + { + $this->wrapWithTestNow(function () { + $this->assertSame('3 hours', Carbon::now()->diffForHumans(Carbon::now()->subHours(3), true)); + $this->assertSame('3 hours', Carbon::now()->diffForHumans(Carbon::now()->addHours(3), true)); + }); + } + + public function testDiffForHumansAbsoluteDays() + { + $this->wrapWithTestNow(function () { + $this->assertSame('2 days', Carbon::now()->diffForHumans(Carbon::now()->subDays(2), true)); + $this->assertSame('2 days', Carbon::now()->diffForHumans(Carbon::now()->addDays(2), true)); + }); + } + + public function testDiffForHumansAbsoluteWeeks() + { + $this->wrapWithTestNow(function () { + $this->assertSame('2 weeks', Carbon::now()->diffForHumans(Carbon::now()->subWeeks(2), true)); + $this->assertSame('2 weeks', Carbon::now()->diffForHumans(Carbon::now()->addWeeks(2), true)); + }); + } + + public function testDiffForHumansAbsoluteMonths() + { + $this->wrapWithTestNow(function () { + $this->assertSame('2 months', Carbon::now()->diffForHumans(Carbon::now()->subMonthsNoOverflow(2), true)); + $this->assertSame('2 months', Carbon::now()->diffForHumans(Carbon::now()->addMonthsNoOverflow(2), true)); + }); + } + + public function testDiffForHumansAbsoluteYears() + { + $this->wrapWithTestNow(function () { + $this->assertSame('1 year', Carbon::now()->diffForHumans(Carbon::now()->subYears(1), true)); + $this->assertSame('1 year', Carbon::now()->diffForHumans(Carbon::now()->addYears(1), true)); + }); + } + + public function testDiffForHumansWithOptions() + { + $this->wrapWithTestNow(function () { + $this->assertSame('1 year', Carbon::now()->diffForHumans(Carbon::now()->subYears(1), CarbonInterface::DIFF_ABSOLUTE)); + $this->assertSame('1 year', Carbon::now()->diffForHumans(Carbon::now()->addYears(1), CarbonInterface::DIFF_ABSOLUTE)); + $this->assertSame('1 year after', Carbon::now()->diffForHumans(Carbon::now()->subYears(1), CarbonInterface::DIFF_RELATIVE_AUTO)); + $this->assertSame('1 year before', Carbon::now()->diffForHumans(Carbon::now()->addYears(1), CarbonInterface::DIFF_RELATIVE_AUTO)); + $this->assertSame('1 year from now', Carbon::now()->diffForHumans(Carbon::now()->subYears(1), CarbonInterface::DIFF_RELATIVE_TO_NOW)); + $this->assertSame('1 year ago', Carbon::now()->diffForHumans(Carbon::now()->addYears(1), CarbonInterface::DIFF_RELATIVE_TO_NOW)); + $this->assertSame('1 year after', Carbon::now()->diffForHumans(Carbon::now()->subYears(1), CarbonInterface::DIFF_RELATIVE_TO_OTHER)); + $this->assertSame('1 year before', Carbon::now()->diffForHumans(Carbon::now()->addYears(1), CarbonInterface::DIFF_RELATIVE_TO_OTHER)); + $this->assertSame('1 year', Carbon::now()->subYears(1)->diffForHumans(null, CarbonInterface::DIFF_ABSOLUTE)); + $this->assertSame('1 year', Carbon::now()->addYears(1)->diffForHumans(null, CarbonInterface::DIFF_ABSOLUTE)); + $this->assertSame('1 year ago', Carbon::now()->subYears(1)->diffForHumans(null, CarbonInterface::DIFF_RELATIVE_AUTO)); + $this->assertSame('1 year from now', Carbon::now()->addYears(1)->diffForHumans(null, CarbonInterface::DIFF_RELATIVE_AUTO)); + $this->assertSame('1 year ago', Carbon::now()->subYears(1)->diffForHumans(null, CarbonInterface::DIFF_RELATIVE_TO_NOW)); + $this->assertSame('1 year from now', Carbon::now()->addYears(1)->diffForHumans(null, CarbonInterface::DIFF_RELATIVE_TO_NOW)); + $this->assertSame('1 year before', Carbon::now()->subYears(1)->diffForHumans(null, CarbonInterface::DIFF_RELATIVE_TO_OTHER)); + $this->assertSame('1 year after', Carbon::now()->addYears(1)->diffForHumans(null, CarbonInterface::DIFF_RELATIVE_TO_OTHER)); + }); + } + + public function testDiffForHumansWithMagicMethods() + { + $this->wrapWithTestNow(function () { + $this->assertSame('1 year', Carbon::now()->longAbsoluteDiffForHumans(Carbon::now()->subYears(1)->subMonth())); + $this->assertSame('1 year 1 month', Carbon::now()->longAbsoluteDiffForHumans(2, Carbon::now()->subYears(1)->subMonth())); + $this->assertSame('1 year 1 month', Carbon::now()->longAbsoluteDiffForHumans(Carbon::now()->subYears(1)->subMonth(), 2)); + $this->assertSame('1 year', Carbon::now()->longAbsoluteDiffForHumans(Carbon::now()->subYears(1))); + $this->assertSame('1 year', Carbon::now()->longAbsoluteDiffForHumans(Carbon::now()->addYears(1))); + $this->assertSame('1yr', Carbon::now()->shortAbsoluteDiffForHumans(Carbon::now()->subYears(1))); + $this->assertSame('1yr', Carbon::now()->shortAbsoluteDiffForHumans(Carbon::now()->addYears(1))); + $this->assertSame('1 year after', Carbon::now()->longRelativeDiffForHumans(Carbon::now()->subYears(1))); + $this->assertSame('1 year before', Carbon::now()->longRelativeDiffForHumans(Carbon::now()->addYears(1))); + $this->assertSame('1yr after', Carbon::now()->shortRelativeDiffForHumans(Carbon::now()->subYears(1))); + $this->assertSame('1yr before', Carbon::now()->shortRelativeDiffForHumans(Carbon::now()->addYears(1))); + $this->assertSame('1 year from now', Carbon::now()->longRelativeToNowDiffForHumans(Carbon::now()->subYears(1))); + $this->assertSame('1 year ago', Carbon::now()->longRelativeToNowDiffForHumans(Carbon::now()->addYears(1))); + $this->assertSame('1yr from now', Carbon::now()->shortRelativeToNowDiffForHumans(Carbon::now()->subYears(1))); + $this->assertSame('1yr ago', Carbon::now()->shortRelativeToNowDiffForHumans(Carbon::now()->addYears(1))); + $this->assertSame('1 year after', Carbon::now()->longRelativeToOtherDiffForHumans(Carbon::now()->subYears(1))); + $this->assertSame('1 year before', Carbon::now()->longRelativeToOtherDiffForHumans(Carbon::now()->addYears(1))); + $this->assertSame('1yr after', Carbon::now()->shortRelativeToOtherDiffForHumans(Carbon::now()->subYears(1))); + $this->assertSame('1yr before', Carbon::now()->shortRelativeToOtherDiffForHumans(Carbon::now()->addYears(1))); + $this->assertSame('1 year', Carbon::now()->subYears(1)->longAbsoluteDiffForHumans()); + $this->assertSame('1 year', Carbon::now()->addYears(1)->longAbsoluteDiffForHumans()); + $this->assertSame('1yr', Carbon::now()->subYears(1)->shortAbsoluteDiffForHumans()); + $this->assertSame('1yr', Carbon::now()->addYears(1)->shortAbsoluteDiffForHumans()); + $this->assertSame('1 year ago', Carbon::now()->subYears(1)->longRelativeDiffForHumans()); + $this->assertSame('1 year from now', Carbon::now()->addYears(1)->longRelativeDiffForHumans()); + $this->assertSame('1yr ago', Carbon::now()->subYears(1)->shortRelativeDiffForHumans()); + $this->assertSame('1yr from now', Carbon::now()->addYears(1)->shortRelativeDiffForHumans()); + $this->assertSame('1 year ago', Carbon::now()->subYears(1)->longRelativeToNowDiffForHumans()); + $this->assertSame('1 year from now', Carbon::now()->addYears(1)->longRelativeToNowDiffForHumans()); + $this->assertSame('1yr ago', Carbon::now()->subYears(1)->shortRelativeToNowDiffForHumans()); + $this->assertSame('1yr from now', Carbon::now()->addYears(1)->shortRelativeToNowDiffForHumans()); + $this->assertSame('1 year before', Carbon::now()->subYears(1)->longRelativeToOtherDiffForHumans()); + $this->assertSame('1 year after', Carbon::now()->addYears(1)->longRelativeToOtherDiffForHumans()); + $this->assertSame('1yr before', Carbon::now()->subYears(1)->shortRelativeToOtherDiffForHumans()); + $this->assertSame('1yr after', Carbon::now()->addYears(1)->shortRelativeToOtherDiffForHumans()); + }); + } + + public function testDiffForHumansWithShorterMonthShouldStillBeAMonth() + { + $feb15 = Carbon::parse('2015-02-15'); + $mar15 = Carbon::parse('2015-03-15'); + $this->assertSame('1 month after', $mar15->diffForHumans($feb15)); + } + + public function testDiffForHumansWithDateTimeInstance() + { + $feb15 = new DateTime('2015-02-15'); + $mar15 = Carbon::parse('2015-03-15'); + $this->assertSame('1 month after', $mar15->diffForHumans($feb15)); + } + + public function testDiffForHumansWithDateString() + { + $mar13 = Carbon::parse('2018-03-13'); + $this->assertSame('1 month before', $mar13->diffForHumans('2018-04-13')); + } + + public function testDiffForHumansWithDateTimeString() + { + $mar13 = Carbon::parse('2018-03-13'); + $this->assertSame('1 month before', $mar13->diffForHumans('2018-04-13 08:00:00')); + } + + public function testDiffWithString() + { + $dt1 = Carbon::createFromDate(2000, 1, 25)->endOfDay(); + + $this->assertSame(384.0, round($dt1->diffInHours('2000-01-10', true))); + $this->assertSame(383.0, floor($dt1->diffInHours('2000-01-10', true))); + } + + public function testDiffWithDateTime() + { + $dt1 = Carbon::createFromDate(2000, 1, 25)->endOfDay(); + $dt2 = new DateTime('2000-01-10'); + + $this->assertSame(-384.0, round($dt1->diffInHours($dt2))); + } + + public function testDiffOptions() + { + $this->assertSame(1, Carbon::NO_ZERO_DIFF); + $this->assertSame(2, Carbon::JUST_NOW); + $this->assertSame(4, Carbon::ONE_DAY_WORDS); + $this->assertSame(8, Carbon::TWO_DAY_WORDS); + $this->assertSame(16, Carbon::SEQUENTIAL_PARTS_ONLY); + + $options = Carbon::getHumanDiffOptions(); + $this->assertSame(0, $options); + + $date = Carbon::create(2018, 3, 12, 2, 5, 6, 'UTC'); + $this->assertSame('0 seconds before', $date->diffForHumans($date)); + + Carbon::setHumanDiffOptions(0); + $this->assertSame(0, Carbon::getHumanDiffOptions()); + + $this->assertSame('0 seconds before', $date->diffForHumans($date)); + + Carbon::setLocale('fr'); + $this->assertSame('0 seconde avant', $date->diffForHumans($date)); + + Carbon::setLocale('en'); + Carbon::setHumanDiffOptions(Carbon::JUST_NOW); + $this->assertSame(2, Carbon::getHumanDiffOptions()); + $this->assertSame('0 seconds before', $date->diffForHumans($date)); + $this->assertSame('just now', Carbon::now()->diffForHumans()); + + Carbon::setHumanDiffOptions(Carbon::ONE_DAY_WORDS | Carbon::TWO_DAY_WORDS | Carbon::NO_ZERO_DIFF | Carbon::SEQUENTIAL_PARTS_ONLY); + $this->assertSame(29, Carbon::getHumanDiffOptions()); + + Carbon::disableHumanDiffOption(Carbon::SEQUENTIAL_PARTS_ONLY); + + $oneDayAfter = Carbon::create(2018, 3, 13, 2, 5, 6, 'UTC'); + $oneDayBefore = Carbon::create(2018, 3, 11, 2, 5, 6, 'UTC'); + $twoDayAfter = Carbon::create(2018, 3, 14, 2, 5, 6, 'UTC'); + $twoDayBefore = Carbon::create(2018, 3, 10, 2, 5, 6, 'UTC'); + + $this->assertSame('1 day after', $oneDayAfter->diffForHumans($date)); + $this->assertSame('1 day before', $oneDayBefore->diffForHumans($date)); + $this->assertSame('2 days after', $twoDayAfter->diffForHumans($date)); + $this->assertSame('2 days before', $twoDayBefore->diffForHumans($date)); + + $this->assertSame('tomorrow', Carbon::now()->addDay()->diffForHumans()); + $this->assertSame('yesterday', Carbon::now()->subDay()->diffForHumans()); + $this->assertSame('after tomorrow', Carbon::now()->addDays(2)->diffForHumans()); + $this->assertSame('before yesterday', Carbon::now()->subDays(2)->diffForHumans()); + + Carbon::disableHumanDiffOption(Carbon::TWO_DAY_WORDS); + $this->assertSame(5, Carbon::getHumanDiffOptions()); + Carbon::disableHumanDiffOption(Carbon::TWO_DAY_WORDS); + $this->assertSame(5, Carbon::getHumanDiffOptions()); + + $this->assertSame('tomorrow', Carbon::now()->addDay()->diffForHumans()); + $this->assertSame('yesterday', Carbon::now()->subDay()->diffForHumans()); + $this->assertSame('2 days from now', Carbon::now()->addDays(2)->diffForHumans()); + $this->assertSame('2 days ago', Carbon::now()->subDays(2)->diffForHumans()); + + Carbon::enableHumanDiffOption(Carbon::JUST_NOW); + $this->assertSame(7, Carbon::getHumanDiffOptions()); + Carbon::enableHumanDiffOption(Carbon::JUST_NOW); + $this->assertSame(7, Carbon::getHumanDiffOptions()); + + $origin = Carbon::create(2019, 1, 4, 0, 0, 0, 'UTC'); + $comparison = Carbon::create(2019, 2, 4, 0, 0, 0, 'UTC'); + $this->assertSame('1 month before', $origin->diffForHumans($comparison, [ + 'parts' => 2, + ])); + $this->assertSame('1 month before', $origin->diffForHumans($comparison, [ + 'parts' => 2, + 'options' => CarbonInterface::SEQUENTIAL_PARTS_ONLY, + ])); + + $origin = Carbon::create(2019, 1, 4, 0, 0, 0, 'UTC'); + $comparison = Carbon::create(2019, 2, 11, 0, 0, 0, 'UTC'); + $this->assertSame('1 month 1 week before', $origin->diffForHumans($comparison, [ + 'parts' => 2, + ])); + $this->assertSame('1 month 1 week before', $origin->diffForHumans($comparison, [ + 'parts' => 2, + 'options' => CarbonInterface::SEQUENTIAL_PARTS_ONLY, + ])); + + $origin = Carbon::create(2019, 1, 4, 0, 0, 0, 'UTC'); + $comparison = Carbon::create(2019, 2, 12, 0, 0, 0, 'UTC'); + $this->assertSame('1 month 1 week before', $origin->diffForHumans($comparison, [ + 'parts' => 2, + ])); + $this->assertSame('1 month 1 week before', $origin->diffForHumans($comparison, [ + 'parts' => 2, + 'options' => CarbonInterface::SEQUENTIAL_PARTS_ONLY, + ])); + $this->assertSame('1 month 1 week 1 day before', $origin->diffForHumans($comparison, [ + 'parts' => 3, + ])); + $this->assertSame('1 month 1 week 1 day before', $origin->diffForHumans($comparison, [ + 'parts' => 3, + 'options' => CarbonInterface::SEQUENTIAL_PARTS_ONLY, + ])); + + $origin = Carbon::create(2019, 1, 4, 0, 0, 0, 'UTC'); + $comparison = Carbon::create(2020, 1, 11, 0, 0, 0, 'UTC'); + $this->assertSame('1 year 1 week before', $origin->diffForHumans($comparison, [ + 'parts' => 2, + ])); + $this->assertSame('1 year before', $origin->diffForHumans($comparison, [ + 'parts' => 2, + 'options' => CarbonInterface::SEQUENTIAL_PARTS_ONLY, + ])); + + $origin = Carbon::create(2019, 1, 4, 0, 0, 0, 'UTC'); + $comparison = Carbon::create(2019, 2, 5, 0, 0, 0, 'UTC'); + $this->assertSame('1 month 1 day before', $origin->diffForHumans($comparison, [ + 'parts' => 2, + ])); + $this->assertSame('1 month before', $origin->diffForHumans($comparison, [ + 'parts' => 2, + 'options' => CarbonInterface::SEQUENTIAL_PARTS_ONLY, + ])); + + $origin = Carbon::create(2019, 1, 4, 0, 0, 0, 'UTC'); + $comparison = Carbon::create(2019, 1, 12, 0, 1, 0, 'UTC'); + $this->assertSame('1 week 1 day before', $origin->diffForHumans($comparison, [ + 'parts' => 2, + ])); + $this->assertSame('1 week 1 day before', $origin->diffForHumans($comparison, [ + 'parts' => 2, + 'options' => CarbonInterface::SEQUENTIAL_PARTS_ONLY, + ])); + $this->assertSame('1 week 1 day 1 minute before', $origin->diffForHumans($comparison, [ + 'parts' => 3, + ])); + $this->assertSame('1 week 1 day before', $origin->diffForHumans($comparison, [ + 'parts' => 3, + 'options' => CarbonInterface::SEQUENTIAL_PARTS_ONLY, + ])); + + Carbon::setHumanDiffOptions($options); + } + + public function testDiffForHumansArrayParameter() + { + Carbon::setTestNow('2000-01-01 00:00:00'); + $date = Carbon::now()->subtract('2 days, 3 hours and 40 minutes'); + $this->assertSame('2 days ago', $date->diffForHumans([ + 'parts' => 1, + 'join' => true, + ])); + $this->assertSame('2 days and 3 hours ago', $date->diffForHumans([ + 'parts' => 2, + 'join' => true, + ])); + $this->assertSame('hace 2 días y 3 horas', $date->copy()->locale('es')->diffForHumans([ + 'parts' => 2, + 'join' => true, + ])); + $this->assertSame('2 days, 3 hours and 40 minutes ago', $date->diffForHumans([ + 'parts' => -1, + 'join' => true, + ])); + $this->assertSame('3 days, 3 hours and 40 minutes before', $date->diffForHumans(Carbon::now()->addDay(), [ + 'parts' => -1, + 'join' => true, + ])); + $this->assertSame('3 days, 3 hours and 40 minutes before', $date->diffForHumans([ + 'other' => Carbon::now()->addDay(), + 'parts' => -1, + 'join' => true, + ])); + $this->assertSame('2 days, 3 hours ago', $date->diffForHumans([ + 'parts' => 2, + 'join' => ', ', + ])); + $this->assertSame('2d, 3h ago', $date->diffForHumans([ + 'parts' => 2, + 'join' => ', ', + 'short' => true, + ])); + $this->assertSame('2 days, 3 hours before', $date->diffForHumans([ + 'parts' => 2, + 'join' => ', ', + 'syntax' => CarbonInterface::DIFF_RELATIVE_TO_OTHER, + ])); + $this->assertSame('yesterday', Carbon::yesterday()->diffForHumans([ + 'options' => CarbonInterface::ONE_DAY_WORDS, + ])); + $this->assertSame('1 day ago', Carbon::yesterday()->diffForHumans([ + 'options' => 0, + ])); + } + + public function testFromNow() + { + Carbon::setLocale('en'); + $this->assertSame('2 days from now', Carbon::now('UTC')->addDays(2)->fromNow()); + Carbon::setLocale('fr'); + $this->assertSame('dans 2 jours', Carbon::now('UTC')->addDays(2)->fromNow()); + Carbon::setLocale('en'); + $this->assertSame('2 days after', Carbon::now('UTC')->addDays(2)->fromNow(CarbonInterface::DIFF_RELATIVE_TO_OTHER)); + $this->assertSame('2d from now', Carbon::now('UTC')->addDays(2)->addHours(5)->fromNow(null, true)); + $this->assertSame('2 days 5 hours', Carbon::now('UTC')->addDays(2)->addHours(5)->fromNow(true, false, 2)); + } + + public function testFromNowBackwardCompatibleSyntax() + { + $date = Carbon::parse('-5 days'); + $this->assertSame('5 days', $date->fromNow(Carbon::now(), true)); + + $date = Carbon::parse('+5 days'); + $this->assertSame('5 days', $date->fromNow(Carbon::now(), true)); + } + + public function testFrom() + { + Carbon::setLocale('en'); + $this->assertSame('2 days from now', Carbon::now()->addDays(2)->from()); + $this->assertSame('2 days from now', Carbon::now()->addDays(2)->from(null)); + $this->assertSame('2 days after', Carbon::now()->addDay()->from(Carbon::now()->subDay())); + Carbon::setLocale('fr'); + $this->assertSame('2 jours après', Carbon::now()->addDay()->from(Carbon::now()->subDay())); + Carbon::setLocale('en'); + $this->assertSame('2 days from now', Carbon::now()->addDay()->from(Carbon::now()->subDay(), CarbonInterface::DIFF_RELATIVE_TO_NOW)); + $this->assertSame('2d after', Carbon::now()->addDay()->addHours(5)->from(Carbon::now()->subDay(), null, true)); + $this->assertSame('2 days 5 hours', Carbon::now()->addDay()->addHours(5)->from(Carbon::now()->subDay(), true, false, 2)); + } + + public function testSince() + { + Carbon::setLocale('en'); + $this->assertSame('2 days from now', Carbon::now()->addDays(2)->since()); + $this->assertSame('2 days from now', Carbon::now()->addDays(2)->since(null)); + $this->assertSame('2 days after', Carbon::now()->addDay()->since(Carbon::now()->subDay())); + Carbon::setLocale('fr'); + $this->assertSame('2 jours après', Carbon::now()->addDay()->since(Carbon::now()->subDay())); + Carbon::setLocale('en'); + $this->assertSame('2 days from now', Carbon::now()->addDay()->since(Carbon::now()->subDay(), CarbonInterface::DIFF_RELATIVE_TO_NOW)); + $this->assertSame('2d after', Carbon::now()->addDay()->addHours(5)->since(Carbon::now()->subDay(), null, true)); + $this->assertSame('2 days 5 hours', Carbon::now()->addDay()->addHours(5)->since(Carbon::now()->subDay(), true, false, 2)); + } + + public function testToNow() + { + Carbon::setLocale('en'); + $this->assertSame('2 days ago', Carbon::now('UTC')->addDays(2)->toNow()); + Carbon::setLocale('fr'); + $this->assertSame('il y a 2 jours', Carbon::now('UTC')->addDays(2)->toNow()); + Carbon::setLocale('en'); + $this->assertSame('2 days before', Carbon::now('UTC')->addDays(2)->toNow(CarbonInterface::DIFF_RELATIVE_TO_OTHER)); + $this->assertSame('2d ago', Carbon::now('UTC')->addDays(2)->addHours(5)->toNow(null, true)); + $this->assertSame('2 days 5 hours', Carbon::now('UTC')->addDays(2)->addHours(5)->toNow(true, false, 2)); + } + + public function testTo() + { + Carbon::setLocale('en'); + $this->assertSame('2 days ago', Carbon::now()->addDays(2)->to()); + $this->assertSame('2 days ago', Carbon::now()->addDays(2)->to(null)); + $this->assertSame('2 days before', Carbon::now()->addDay()->to(Carbon::now()->subDay())); + Carbon::setLocale('fr'); + $this->assertSame('2 jours avant', Carbon::now()->addDay()->to(Carbon::now()->subDay())); + Carbon::setLocale('en'); + $this->assertSame('2 days ago', Carbon::now()->addDay()->to(Carbon::now()->subDay(), CarbonInterface::DIFF_RELATIVE_TO_NOW)); + $this->assertSame('2d before', Carbon::now()->addDay()->addHours(5)->to(Carbon::now()->subDay(), null, true)); + $this->assertSame('2 days 5 hours', Carbon::now()->addDay()->addHours(5)->to(Carbon::now()->subDay(), true, false, 2)); + } + + public function testUntil() + { + Carbon::setLocale('en'); + $this->assertSame('2 days ago', Carbon::now()->addDays(2)->until()); + $this->assertSame('2 days ago', Carbon::now()->addDays(2)->until(null)); + $this->assertSame('2 days before', Carbon::now()->addDay()->until(Carbon::now()->subDay())); + Carbon::setLocale('fr'); + $this->assertSame('2 jours avant', Carbon::now()->addDay()->until(Carbon::now()->subDay())); + Carbon::setLocale('en'); + $this->assertSame('2 days ago', Carbon::now()->addDay()->until(Carbon::now()->subDay(), CarbonInterface::DIFF_RELATIVE_TO_NOW)); + $this->assertSame('2d before', Carbon::now()->addDay()->addHours(5)->until(Carbon::now()->subDay(), null, true)); + $this->assertSame('2 days 5 hours', Carbon::now()->addDay()->addHours(5)->until(Carbon::now()->subDay(), true, false, 2)); + } + + public function testDiffWithInvalidType() + { + $this->expectException(TypeError::class); + + Carbon::createFromDate(2000, 1, 25)->diffInHours(10); + } + + public function testDiffWithInvalidObject() + { + $this->expectException(TypeError::class); + + Carbon::createFromDate(2000, 1, 25)->diffInHours(new CarbonInterval()); + } + + public function testDiffForHumansWithIncorrectDateTimeStringWhichIsNotACarbonInstance() + { + $this->expectException(InvalidFormatException::class); + $this->expectExceptionMessage('Failed to parse time string (2018-04-13---08:00:00) at position 10'); + + $mar13 = Carbon::parse('2018-03-13'); + $mar13->diffForHumans('2018-04-13---08:00:00'); + } + + public function testFloatDiff() + { + date_default_timezone_set('UTC'); + + $this->assertSame(8986.665965, Carbon::parse('2018-03-31 23:55:12.321456')->floatDiffInSeconds(Carbon::parse('2018-04-01 02:24:58.987421'))); + + $this->assertVeryClose(1.0006944444444443, Carbon::parse('2018-12-01 00:00')->floatDiffInDays(Carbon::parse('2018-12-02 00:01'))); + $this->assertVeryClose(1.0006944444444443 / 7, Carbon::parse('2018-12-01 00:00')->floatDiffInWeeks(Carbon::parse('2018-12-02 00:01'))); + + $this->assertVeryClose(0.959000397985738, Carbon::parse('2018-03-13 20:55:12.321456')->floatDiffInMonths(Carbon::parse('2018-04-12 14:24:58.987421'), true)); + $this->assertVeryClose(0.959000397985738, Carbon::parse('2018-04-12 14:24:58.987421')->floatDiffInMonths(Carbon::parse('2018-03-13 20:55:12.321456'), true)); + $this->assertVeryClose(0.959000397985738, Carbon::parse('2018-03-13 20:55:12.321456')->floatDiffInMonths(Carbon::parse('2018-04-12 14:24:58.987421'))); + $this->assertVeryClose(-0.959000397985738, Carbon::parse('2018-04-12 14:24:58.987421')->floatDiffInMonths(Carbon::parse('2018-03-13 20:55:12.321456'))); + + $this->assertVeryClose(16.557633744585264, Carbon::parse('2018-02-13 20:55:12.321456')->floatDiffInMonths(Carbon::parse('2019-06-30 14:24:58.987421'), true)); + + $this->assertVeryClose(15.959000397985738, Carbon::parse('2018-02-13 20:55:12.321456')->floatDiffInMonths(Carbon::parse('2019-06-12 14:24:58.987421'), true)); + $this->assertVeryClose(15.959000397985738, Carbon::parse('2019-06-12 14:24:58.987421')->floatDiffInMonths(Carbon::parse('2018-02-13 20:55:12.321456'), true)); + $this->assertVeryClose(15.959000397985738, Carbon::parse('2018-02-13 20:55:12.321456')->floatDiffInMonths(Carbon::parse('2019-06-12 14:24:58.987421'))); + $this->assertVeryClose(-15.959000397985738, Carbon::parse('2019-06-12 14:24:58.987421')->floatDiffInMonths(Carbon::parse('2018-02-13 20:55:12.321456'))); + + $this->assertSame(1.0, Carbon::parse('2018-02-13 20:55:12.321456')->floatDiffInYears(Carbon::parse('2019-02-13 20:55:12.321456'), true)); + $this->assertVeryClose(1.3746000338015283, Carbon::parse('2018-02-13 20:55:12.321456')->floatDiffInYears(Carbon::parse('2019-06-30 14:24:58.987421'), true)); + $this->assertVeryClose(0.9609014036645421, Carbon::parse('2018-02-13 20:55:12.321456')->floatDiffInYears(Carbon::parse('2019-01-30 14:24:58.987421'), true)); + + $this->assertVeryClose(1.3252849653083778, Carbon::parse('2018-02-13 20:55:12.321456')->floatDiffInYears(Carbon::parse('2019-06-12 14:24:58.987421'), true)); + $this->assertVeryClose(1.3252849653083778, Carbon::parse('2019-06-12 14:24:58.987421')->floatDiffInYears(Carbon::parse('2018-02-13 20:55:12.321456'), true)); + $this->assertVeryClose(1.3252849653083778, Carbon::parse('2018-02-13 20:55:12.321456')->floatDiffInYears(Carbon::parse('2019-06-12 14:24:58.987421'))); + $this->assertVeryClose(-1.3252849653083778, Carbon::parse('2019-06-12 14:24:58.987421')->floatDiffInYears(Carbon::parse('2018-02-13 20:55:12.321456'))); + + $this->assertVeryClose(5.325284965308378, Carbon::parse('2018-02-13 20:55:12.321456')->floatDiffInYears(Carbon::parse('2023-06-12 14:24:58.987421'), true)); + $this->assertVeryClose(5.325284965308378, Carbon::parse('2023-06-12 14:24:58.987421')->floatDiffInYears(Carbon::parse('2018-02-13 20:55:12.321456'), true)); + $this->assertVeryClose(5.325284965308378, Carbon::parse('2018-02-13 20:55:12.321456')->floatDiffInYears(Carbon::parse('2023-06-12 14:24:58.987421'))); + $this->assertVeryClose(-5.325284965308378, Carbon::parse('2023-06-12 14:24:58.987421')->floatDiffInYears(Carbon::parse('2018-02-13 20:55:12.321456'))); + + $this->assertSame(1.0, Carbon::parse('2018-10-01 00:00:00', 'Europe/Paris')->floatDiffInMonths(Carbon::parse('2018-11-01 00:00:00', 'Europe/Paris'), true)); + $this->assertSame(1.0, Carbon::parse('2018-10-28 00:00:00')->floatDiffInMonths(Carbon::parse('2018-11-28 00:00:00'), true)); + $this->assertSame(1.0, Carbon::parse('2018-10-28 00:00:00', 'Europe/Paris')->floatDiffInMonths(Carbon::parse('2018-11-28 00:00:00', 'Europe/Paris'), true)); + + $this->assertVeryClose(-0.9999999999884258, Carbon::parse('2020-12-17 00:00:00.000001')->floatDiffInDays('2020-12-16 00:00:00.000002')); + + $this->assertSame(-1.0, Carbon::parse('2018-11-01 00:00:00', 'Europe/Paris')->floatDiffInMonths(Carbon::parse('2018-10-01 00:00:00', 'Europe/Paris'))); + $this->assertSame(-1.0, Carbon::parse('2018-11-28 00:00:00')->floatDiffInMonths(Carbon::parse('2018-10-28 00:00:00'))); + $this->assertSame(-1.0, Carbon::parse('2018-11-28 00:00:00', 'Europe/Paris')->floatDiffInMonths(Carbon::parse('2018-10-28 00:00:00', 'Europe/Paris'))); + } + + public function testFloatDiffWithRealUnits() + { + $from = Carbon::parse('2021-03-27 20:00 Europe/Warsaw'); + $to = Carbon::parse('2021-03-27 20:00 Europe/London'); + $from->floatDiffInRealDays($to); + + $this->assertSame('2021-03-27 20:00:00 Europe/Warsaw', $from->format('Y-m-d H:i:s e')); + $this->assertSame('2021-03-27 20:00:00 Europe/London', $to->format('Y-m-d H:i:s e')); + + date_default_timezone_set('UTC'); + $this->assertVeryClose(1.0006944444444446, Carbon::parse('2018-12-01 00:00')->floatDiffInRealDays(Carbon::parse('2018-12-02 00:01'), true)); + + $this->assertVeryClose(0.9583333333333334, Carbon::parse('2021-03-27 20:00 Europe/Warsaw')->floatDiffInRealDays('2021-03-28 20:00')); + $this->assertVeryClose(1.9583333333333335, Carbon::parse('2021-03-26 20:00 Europe/Warsaw')->floatDiffInRealDays('2021-03-28 20:00')); + $this->assertVeryClose(1.9583333333333335, Carbon::parse('2021-03-27 20:00 Europe/Warsaw')->floatDiffInRealDays('2021-03-29 20:00')); + $this->assertVeryClose(1.0416666666666667, Carbon::parse('2021-10-30 20:00 Europe/Warsaw')->floatDiffInRealDays('2021-10-31 20:00')); + $this->assertVeryClose(1.0006944444444443, Carbon::parse('2018-12-01 00:00')->floatDiffInRealDays(Carbon::parse('2018-12-02 00:01'))); + + $this->assertVeryClose(1.0006944444444443, Carbon::parse('2018-12-01 00:00')->floatDiffInRealDays(Carbon::parse('2018-12-02 00:01'))); + $this->assertVeryClose(1.0006944444444443 / 7, Carbon::parse('2018-12-01 00:00')->floatDiffInRealWeeks(Carbon::parse('2018-12-02 00:01'))); + + $this->assertVeryClose(0.9590003979857377, Carbon::parse('2018-03-13 20:55:12.321456')->floatDiffInRealMonths(Carbon::parse('2018-04-12 14:24:58.987421'), true)); + $this->assertVeryClose(0.9590003979857377, Carbon::parse('2018-04-12 14:24:58.987421')->floatDiffInRealMonths(Carbon::parse('2018-03-13 20:55:12.321456'), true)); + $this->assertVeryClose(0.9590003979857377, Carbon::parse('2018-03-13 20:55:12.321456')->floatDiffInRealMonths(Carbon::parse('2018-04-12 14:24:58.987421'), false)); + $this->assertVeryClose(-0.9590003979857377, Carbon::parse('2018-04-12 14:24:58.987421')->floatDiffInRealMonths(Carbon::parse('2018-03-13 20:55:12.321456'), false)); + + $this->assertVeryClose(1.0006944444444443 / 7, Carbon::parse('2018-12-01 00:00')->floatDiffInRealWeeks(Carbon::parse('2018-12-02 00:01'))); + $this->assertVeryClose(1.0006944444444443 / 7, Carbon::parse('2018-12-01 00:00')->floatDiffInRealWeeks(Carbon::parse('2018-12-02 00:01'), true)); + + $this->assertVeryClose(0.9590003979857377, Carbon::parse('2018-03-13 20:55:12.321456')->floatDiffInRealMonths(Carbon::parse('2018-04-12 14:24:58.987421'))); + $this->assertVeryClose(-0.9590003979857377, Carbon::parse('2018-04-12 14:24:58.987421')->floatDiffInRealMonths(Carbon::parse('2018-03-13 20:55:12.321456'))); + + $this->assertVeryClose(16.557633744585264, Carbon::parse('2018-02-13 20:55:12.321456')->floatDiffInRealMonths(Carbon::parse('2019-06-30 14:24:58.987421'), true)); + + $this->assertVeryClose(15.9590003979857377, Carbon::parse('2018-02-13 20:55:12.321456')->floatDiffInRealMonths(Carbon::parse('2019-06-12 14:24:58.987421'), true)); + $this->assertVeryClose(15.9590003979857377, Carbon::parse('2019-06-12 14:24:58.987421')->floatDiffInRealMonths(Carbon::parse('2018-02-13 20:55:12.321456'), true)); + $this->assertVeryClose(15.9590003979857377, Carbon::parse('2018-02-13 20:55:12.321456')->floatDiffInRealMonths(Carbon::parse('2019-06-12 14:24:58.987421'))); + $this->assertVeryClose(-15.9590003979857377, Carbon::parse('2019-06-12 14:24:58.987421')->floatDiffInRealMonths(Carbon::parse('2018-02-13 20:55:12.321456'))); + + $this->assertSame(1.0, Carbon::parse('2018-02-13 20:55:12.321456')->floatDiffInRealYears(Carbon::parse('2019-02-13 20:55:12.321456'), true)); + $this->assertVeryClose(1.3746000338015283, Carbon::parse('2018-02-13 20:55:12.321456')->floatDiffInRealYears(Carbon::parse('2019-06-30 14:24:58.987421'), true)); + $this->assertVeryClose(0.9609014036645421, Carbon::parse('2018-02-13 20:55:12.321456')->floatDiffInRealYears(Carbon::parse('2019-01-30 14:24:58.987421'), true)); + + $this->assertVeryClose(1.3252849653083778, Carbon::parse('2018-02-13 20:55:12.321456')->floatDiffInRealYears(Carbon::parse('2019-06-12 14:24:58.987421'), true)); + $this->assertVeryClose(1.3252849653083778, Carbon::parse('2019-06-12 14:24:58.987421')->floatDiffInRealYears(Carbon::parse('2018-02-13 20:55:12.321456'), true)); + $this->assertVeryClose(1.3252849653083778, Carbon::parse('2018-02-13 20:55:12.321456')->floatDiffInRealYears(Carbon::parse('2019-06-12 14:24:58.987421'))); + $this->assertVeryClose(-1.3252849653083778, Carbon::parse('2019-06-12 14:24:58.987421')->floatDiffInRealYears(Carbon::parse('2018-02-13 20:55:12.321456'))); + + $this->assertVeryClose(5.325284965308378, Carbon::parse('2018-02-13 20:55:12.321456')->floatDiffInRealYears(Carbon::parse('2023-06-12 14:24:58.987421'), true)); + $this->assertVeryClose(5.325284965308378, Carbon::parse('2023-06-12 14:24:58.987421')->floatDiffInRealYears(Carbon::parse('2018-02-13 20:55:12.321456'), true)); + $this->assertVeryClose(5.325284965308378, Carbon::parse('2018-02-13 20:55:12.321456')->floatDiffInRealYears(Carbon::parse('2023-06-12 14:24:58.987421'))); + $this->assertVeryClose(-5.325284965308378, Carbon::parse('2023-06-12 14:24:58.987421')->floatDiffInRealYears(Carbon::parse('2018-02-13 20:55:12.321456'))); + + $this->assertVeryClose(1.0336021505376345, Carbon::parse('2018-10-01 00:00:00', 'Europe/Paris')->floatDiffInRealMonths(Carbon::parse('2018-11-01 00:00:00', 'Europe/Paris'), true)); + $this->assertSame(1.0, Carbon::parse('2018-10-28 00:00:00')->floatDiffInRealMonths(Carbon::parse('2018-11-28 00:00:00'), true)); + $this->assertVeryClose(1.0013888888888889, Carbon::parse('2018-10-28 00:00:00', 'Europe/Paris')->floatDiffInRealMonths(Carbon::parse('2018-11-28 00:00:00', 'Europe/Paris'), true)); + + $this->assertVeryClose(-1.0336021505376345, Carbon::parse('2018-11-01 00:00:00', 'Europe/Paris')->floatDiffInRealMonths(Carbon::parse('2018-10-01 00:00:00', 'Europe/Paris'))); + $this->assertSame(-1.0, Carbon::parse('2018-11-28 00:00:00')->floatDiffInRealMonths(Carbon::parse('2018-10-28 00:00:00'))); + $this->assertVeryClose(-1.0013888888888889, Carbon::parse('2018-11-28 00:00:00', 'Europe/Paris')->floatDiffInRealMonths(Carbon::parse('2018-10-28 00:00:00', 'Europe/Paris'))); + + Carbon::setTestNow('2021-03-28 20:00 Europe/Warsaw'); + $this->assertSame(0.9583333333333334, Carbon::parse('2021-03-27 20:00 Europe/Warsaw')->floatDiffInRealDays()); + } + + public function testFloatDiffWithUTCUnits() + { + $from = Carbon::parse('2021-03-27 20:00 Europe/Warsaw'); + $to = Carbon::parse('2021-03-27 20:00 Europe/London'); + $from->floatDiffInUtcDays($to); + + $this->assertSame('2021-03-27 20:00:00 Europe/Warsaw', $from->format('Y-m-d H:i:s e')); + $this->assertSame('2021-03-27 20:00:00 Europe/London', $to->format('Y-m-d H:i:s e')); + + date_default_timezone_set('UTC'); + $this->assertVeryClose(1.0006944444444446, Carbon::parse('2018-12-01 00:00')->floatDiffInUtcDays(Carbon::parse('2018-12-02 00:01'), true)); + + $this->assertVeryClose(0.9583333333333334, Carbon::parse('2021-03-27 20:00 Europe/Warsaw')->floatDiffInUtcDays('2021-03-28 20:00')); + $this->assertVeryClose(1.9583333333333335, Carbon::parse('2021-03-26 20:00 Europe/Warsaw')->floatDiffInUtcDays('2021-03-28 20:00')); + $this->assertVeryClose(1.9583333333333335, Carbon::parse('2021-03-27 20:00 Europe/Warsaw')->floatDiffInUtcDays('2021-03-29 20:00')); + $this->assertVeryClose(1.0416666666666667, Carbon::parse('2021-10-30 20:00 Europe/Warsaw')->floatDiffInUtcDays('2021-10-31 20:00')); + $this->assertVeryClose(1.0006944444444443, Carbon::parse('2018-12-01 00:00')->floatDiffInUtcDays(Carbon::parse('2018-12-02 00:01'))); + + $this->assertVeryClose(1.0006944444444443, Carbon::parse('2018-12-01 00:00')->floatDiffInUtcDays(Carbon::parse('2018-12-02 00:01'))); + $this->assertVeryClose(1.0006944444444443 / 7, Carbon::parse('2018-12-01 00:00')->floatDiffInUtcWeeks(Carbon::parse('2018-12-02 00:01'))); + + $this->assertVeryClose(0.9590003979857377, Carbon::parse('2018-03-13 20:55:12.321456')->floatDiffInUtcMonths(Carbon::parse('2018-04-12 14:24:58.987421'), true)); + $this->assertVeryClose(0.9590003979857377, Carbon::parse('2018-04-12 14:24:58.987421')->floatDiffInUtcMonths(Carbon::parse('2018-03-13 20:55:12.321456'), true)); + $this->assertVeryClose(0.9590003979857377, Carbon::parse('2018-03-13 20:55:12.321456')->floatDiffInUtcMonths(Carbon::parse('2018-04-12 14:24:58.987421'), false)); + $this->assertVeryClose(-0.9590003979857377, Carbon::parse('2018-04-12 14:24:58.987421')->floatDiffInUtcMonths(Carbon::parse('2018-03-13 20:55:12.321456'), false)); + + $this->assertVeryClose(1.0006944444444443 / 7, Carbon::parse('2018-12-01 00:00')->floatDiffInUtcWeeks(Carbon::parse('2018-12-02 00:01'))); + $this->assertVeryClose(1.0006944444444443 / 7, Carbon::parse('2018-12-01 00:00')->floatDiffInUtcWeeks(Carbon::parse('2018-12-02 00:01'), true)); + + $this->assertVeryClose(0.9590003979857377, Carbon::parse('2018-03-13 20:55:12.321456')->floatDiffInUtcMonths(Carbon::parse('2018-04-12 14:24:58.987421'))); + $this->assertVeryClose(-0.9590003979857377, Carbon::parse('2018-04-12 14:24:58.987421')->floatDiffInUtcMonths(Carbon::parse('2018-03-13 20:55:12.321456'))); + + $this->assertVeryClose(16.557633744585264, Carbon::parse('2018-02-13 20:55:12.321456')->floatDiffInUtcMonths(Carbon::parse('2019-06-30 14:24:58.987421'), true)); + + $this->assertVeryClose(15.9590003979857377, Carbon::parse('2018-02-13 20:55:12.321456')->floatDiffInUtcMonths(Carbon::parse('2019-06-12 14:24:58.987421'), true)); + $this->assertVeryClose(15.9590003979857377, Carbon::parse('2019-06-12 14:24:58.987421')->floatDiffInUtcMonths(Carbon::parse('2018-02-13 20:55:12.321456'), true)); + $this->assertVeryClose(15.9590003979857377, Carbon::parse('2018-02-13 20:55:12.321456')->floatDiffInUtcMonths(Carbon::parse('2019-06-12 14:24:58.987421'))); + $this->assertVeryClose(-15.9590003979857377, Carbon::parse('2019-06-12 14:24:58.987421')->floatDiffInUtcMonths(Carbon::parse('2018-02-13 20:55:12.321456'))); + + $this->assertSame(1.0, Carbon::parse('2018-02-13 20:55:12.321456')->floatDiffInUtcYears(Carbon::parse('2019-02-13 20:55:12.321456'), true)); + $this->assertVeryClose(1.3746000338015283, Carbon::parse('2018-02-13 20:55:12.321456')->floatDiffInUtcYears(Carbon::parse('2019-06-30 14:24:58.987421'), true)); + $this->assertVeryClose(0.9609014036645421, Carbon::parse('2018-02-13 20:55:12.321456')->floatDiffInUtcYears(Carbon::parse('2019-01-30 14:24:58.987421'), true)); + + $this->assertVeryClose(1.3252849653083778, Carbon::parse('2018-02-13 20:55:12.321456')->floatDiffInUtcYears(Carbon::parse('2019-06-12 14:24:58.987421'), true)); + $this->assertVeryClose(1.3252849653083778, Carbon::parse('2019-06-12 14:24:58.987421')->floatDiffInUtcYears(Carbon::parse('2018-02-13 20:55:12.321456'), true)); + $this->assertVeryClose(1.3252849653083778, Carbon::parse('2018-02-13 20:55:12.321456')->floatDiffInUtcYears(Carbon::parse('2019-06-12 14:24:58.987421'))); + $this->assertVeryClose(-1.3252849653083778, Carbon::parse('2019-06-12 14:24:58.987421')->floatDiffInUtcYears(Carbon::parse('2018-02-13 20:55:12.321456'))); + + $this->assertVeryClose(5.325284965308378, Carbon::parse('2018-02-13 20:55:12.321456')->floatDiffInUtcYears(Carbon::parse('2023-06-12 14:24:58.987421'), true)); + $this->assertVeryClose(5.325284965308378, Carbon::parse('2023-06-12 14:24:58.987421')->floatDiffInUtcYears(Carbon::parse('2018-02-13 20:55:12.321456'), true)); + $this->assertVeryClose(5.325284965308378, Carbon::parse('2018-02-13 20:55:12.321456')->floatDiffInUtcYears(Carbon::parse('2023-06-12 14:24:58.987421'))); + $this->assertVeryClose(-5.325284965308378, Carbon::parse('2023-06-12 14:24:58.987421')->floatDiffInUtcYears(Carbon::parse('2018-02-13 20:55:12.321456'))); + + $this->assertVeryClose(1.0336021505376345, Carbon::parse('2018-10-01 00:00:00', 'Europe/Paris')->floatDiffInUtcMonths(Carbon::parse('2018-11-01 00:00:00', 'Europe/Paris'), true)); + $this->assertSame(1.0, Carbon::parse('2018-10-28 00:00:00')->floatDiffInUtcMonths(Carbon::parse('2018-11-28 00:00:00'), true)); + $this->assertVeryClose(1.0013888888888889, Carbon::parse('2018-10-28 00:00:00', 'Europe/Paris')->floatDiffInUtcMonths(Carbon::parse('2018-11-28 00:00:00', 'Europe/Paris'), true)); + + $this->assertVeryClose(-1.0336021505376345, Carbon::parse('2018-11-01 00:00:00', 'Europe/Paris')->floatDiffInUtcMonths(Carbon::parse('2018-10-01 00:00:00', 'Europe/Paris'))); + $this->assertSame(-1.0, Carbon::parse('2018-11-28 00:00:00')->floatDiffInUtcMonths(Carbon::parse('2018-10-28 00:00:00'))); + $this->assertVeryClose(-1.0013888888888889, Carbon::parse('2018-11-28 00:00:00', 'Europe/Paris')->floatDiffInUtcMonths(Carbon::parse('2018-10-28 00:00:00', 'Europe/Paris'))); + + Carbon::setTestNow('2021-03-28 20:00 Europe/Warsaw'); + $this->assertSame(0.9583333333333334, Carbon::parse('2021-03-27 20:00 Europe/Warsaw')->floatDiffInUtcDays()); + } + + /** + * https://bugs.php.net/bug.php?id=77007 + * https://github.com/briannesbitt/Carbon/issues/1503 + */ + public function testPhpBug77007() + { + $this->assertSame(-3.0, Carbon::now()->addMinutes(3)->diffInMinutes()); + + $startDate = Carbon::parse('2018-10-11 20:59:06.914653'); + $endDate = Carbon::parse('2018-10-11 20:59:07.237419'); + + $this->assertSame(0.322766, $startDate->diffInSeconds($endDate)); + + $startDate = Carbon::parse('2018-10-11 20:59:06.914653'); + $endDate = Carbon::parse('2018-10-11 20:59:07.237419'); + + $this->assertSame('+ 00-00-00 00:00:00.322766', $startDate->diff($endDate)->format('%R %Y-%M-%D %H:%I:%S.%F')); + $this->assertSame(0.322766, $startDate->diffInSeconds($endDate)); + + $startDate = Carbon::parse('2018-10-11 20:59:06.914653'); + $endDate = Carbon::parse('2018-10-11 20:59:05.237419'); + + $this->assertSame('+ 00-00-00 00:00:01.677234', $startDate->diff($endDate, true)->format('%R %Y-%M-%D %H:%I:%S.%F')); + $this->assertSame(1.677234, $startDate->diffInSeconds($endDate, true)); + + $this->assertSame('- 00-00-00 00:00:01.677234', $startDate->diff($endDate)->format('%R %Y-%M-%D %H:%I:%S.%F')); + $this->assertSame(-1.677234, $startDate->diffInSeconds($endDate, false)); + + $startDate = Carbon::parse('2018-10-11 20:59:06.914653'); + $endDate = Carbon::parse('2018-10-11 20:59:06.237419'); + + $this->assertSame('+ 00-00-00 00:00:00.677234', $startDate->diff($endDate, true)->format('%R %Y-%M-%D %H:%I:%S.%F')); + $this->assertSame(0.677234, $startDate->diffInSeconds($endDate, true)); + + $this->assertSame('- 00-00-00 00:00:00.677234', $startDate->diff($endDate)->format('%R %Y-%M-%D %H:%I:%S.%F')); + $this->assertSame(-0.677234, $startDate->diffInSeconds($endDate, false)); + + $startDate = Carbon::parse('2017-12-31 23:59:59.914653'); + $endDate = Carbon::parse('2018-01-01 00:00:00.237419'); + + $this->assertSame('+ 00-00-00 00:00:00.322766', $startDate->diff($endDate)->format('%R %Y-%M-%D %H:%I:%S.%F')); + $this->assertSame(0.322766, $startDate->diffInSeconds($endDate)); + } + + public function testPHPBug80974() + { + $this->assertSame(3, Carbon::parse('2018-07-01 America/Toronto')->diffAsDateInterval('2018-07-02 America/Vancouver')->h); + $this->assertSame(0, Carbon::parse('2018-07-01')->utc()->diffAsDateInterval('2018-07-02')->days); + $this->assertSame(1, Carbon::parse('2018-07-01')->utc()->diffAsDateInterval(Carbon::parse('2018-07-02'))->days); + $this->assertSame(1, Carbon::parse('2018-07-01')->diffAsDateInterval(Carbon::parse('2018-07-02')->utc())->days); + } + + public function testThreeMonthMinusOneDay() + { + $start = new Carbon('2022-11-11 22:29:50.000000'); + $end = $start->addMonths(3); + $now = $start->addDay(); + + $this->assertSame(3.0, $start->diffInMonths($end)); + $this->assertSame(3 - 1 / 31, $now->diffInMonths($end)); + + $start = new Carbon('2022-04-11 22:29:50.000000'); + $end = $start->addMonths(3); + $now = $start->addDay(); + + $this->assertSame(3.0, $start->diffInMonths($end)); + $this->assertSame(3 - 1 / 30, $now->diffInMonths($end)); + } + + public function testDiffWithZeroAndNonZeroMicroseconds() + { + $requestTime = new Carbon('2018-11-14 18:23:12.0 +00:00'); + $serverTime = new Carbon('2018-11-14 18:23:12.307628 +00:00'); + + $this->assertSame(-0.307628, $serverTime->diffInSeconds($requestTime)); + + $requestTime = new Carbon('2019-02-10 18:23:12.0 +00:00'); + $serverTime = new Carbon('2019-02-10 18:23:12.307628 +00:00'); + + $this->assertSame(-0.307628, $serverTime->diffInSeconds($requestTime)); + } + + public function testNearlyFullDayDiffInSeconds() + { + $d1 = Carbon::parse('2019-06-15 12:34:56.123456'); + $d2 = Carbon::parse('2019-06-16 12:34:56.123455'); + + $this->assertVeryClose(-86399.99999899999, $d2->diffInSeconds($d1)); + } + + public function testNearlyFullDayDiffInMicroseconds() + { + $d1 = Carbon::parse('2019-06-15 12:34:56.123456'); + $d2 = Carbon::parse('2019-06-16 12:34:56.123455'); + + $this->assertVeryClose(-86399999999.0, $d2->diffInMicroseconds($d1)); + } + + public function testExactMonthDiffInSeconds() + { + $d1 = Carbon::make('2019-01-23 12:00:00'); + $d2 = Carbon::make('2019-02-23 12:00:00'); + + $this->assertSame(-2678400.0, $d2->diffInSeconds($d1)); + } + + public function testDiffInUnit() + { + $this->assertSame(5.5, Carbon::make('2020-08-13 05:00')->diffInUnit('hour', '2020-08-13 10:30')); + } + + public function testDiffInUnitException() + { + $this->expectException(UnknownUnitException::class); + $this->expectExceptionMessage("Unknown unit 'moons'."); + $this->assertSame(5.5, Carbon::make('2020-08-13 05:00')->diffInUnit('moon', '2020-08-13 10:30')); + } + + public function testDaysDiffPreservation() + { + $deletedDate = Carbon::now()->startOfDay()->addDays(31); + + $this->assertSame('31 days', $deletedDate->diffForHumans(Carbon::now()->startOfDay(), [ + 'syntax' => CarbonInterface::DIFF_ABSOLUTE, + 'skip' => ['m', 'w'], + 'minimumUnit' => 'd', + ])); + + $this->assertSame('31 days', $deletedDate->diffForHumans(Carbon::now()->startOfDay()->subHours(5), [ + 'syntax' => CarbonInterface::DIFF_ABSOLUTE, + 'skip' => ['m', 'w'], + 'minimumUnit' => 'd', + ])); + + $this->assertSame('30 days', $deletedDate->diffForHumans(Carbon::now()->startOfDay()->addHours(5), [ + 'syntax' => CarbonInterface::DIFF_ABSOLUTE, + 'skip' => ['m', 'w'], + 'minimumUnit' => 'd', + ])); + } + + public function testAFormat() + { + $past = new Carbon('-3 Days'); + $today = new Carbon('today'); + $interval = $today->diff($past); + + $this->assertSame('2', $interval->format('%a')); + } +} diff --git a/tests/CarbonImmutable/GenericMacroTest.php b/tests/CarbonImmutable/GenericMacroTest.php new file mode 100644 index 0000000..6a66455 --- /dev/null +++ b/tests/CarbonImmutable/GenericMacroTest.php @@ -0,0 +1,159 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Tests\CarbonImmutable; + +use BadMethodCallException; +use Carbon\CarbonImmutable as Carbon; +use Tests\AbstractTestCaseWithOldNow; +use Throwable; + +class GenericMacroTest extends AbstractTestCaseWithOldNow +{ + public function testGenericMacro() + { + Carbon::genericMacro(function ($method) { + $time = preg_replace('/[A-Z]/', ' $0', $method); + + try { + return self::this()->modify($time); + } catch (Throwable $exception) { + if (preg_match('(Could not modify with|Failed to parse)', $exception->getMessage())) { + throw new BadMethodCallException('Try next macro', 0, $exception); + } + + throw $exception; + } + }); + + /** @var mixed $now */ + $now = Carbon::now(); + + $this->assertSame('2017-07-02', $now->nextSunday()->format('Y-m-d')); + $this->assertSame('2017-06-26', Carbon::lastMonday()->format('Y-m-d')); + + $message = null; + + try { + Carbon::fooBar(); + } catch (BadMethodCallException $exception) { + $message = $exception->getMessage(); + } + + $this->assertSame('Method '.Carbon::class.'::fooBar does not exist.', $message); + + $message = null; + + try { + $now->barBiz(); + } catch (BadMethodCallException $exception) { + $message = $exception->getMessage(); + } + + $this->assertSame('Method barBiz does not exist.', $message); + } + + public function testGenericMacroPriority() + { + Carbon::genericMacro(function ($method) { + if (!str_starts_with($method, 'myPrefix')) { + throw new BadMethodCallException('Try next macro', 0); + } + + return 'first'; + }); + Carbon::genericMacro(function ($method) { + if (!str_starts_with($method, 'myPrefix')) { + throw new BadMethodCallException('Try next macro', 0); + } + + return 'second'; + }, 1); + Carbon::genericMacro(function ($method) { + if (!str_starts_with($method, 'myPrefix')) { + throw new BadMethodCallException('Try next macro', 0); + } + + return 'third'; + }, -1); + Carbon::macro('myPrefixFooBar', function () { + return 'myPrefixFooBar'; + }); + + /** @var mixed $now */ + $now = Carbon::now(); + + $this->assertSame('second', $now->myPrefixSomething()); + $this->assertSame('second', Carbon::myPrefixSomething()); + $this->assertSame('myPrefixFooBar', $now->myPrefixFooBar()); + $this->assertSame('myPrefixFooBar', Carbon::myPrefixFooBar()); + } + + public function testLocalGenericMacroPriority() + { + Carbon::genericMacro(function ($method) { + if (!str_starts_with($method, 'mlp')) { + throw new BadMethodCallException('Try next macro', 0); + } + + return 'first'; + }); + Carbon::genericMacro(function ($method) { + if (!str_starts_with($method, 'mlp')) { + throw new BadMethodCallException('Try next macro', 0); + } + + return 'second'; + }, 1); + Carbon::genericMacro(function ($method) { + if (!str_starts_with($method, 'mlp')) { + throw new BadMethodCallException('Try next macro', 0); + } + + return 'third'; + }, -1); + Carbon::macro('mlpFooBar', function () { + return 'mlpFooBar'; + }); + + /** @var mixed $date */ + $date = Carbon::now()->settings([ + 'genericMacros' => [ + function ($method) { + if (!str_starts_with($method, 'mlp')) { + throw new BadMethodCallException('Try next macro', 0); + } + + return 'local-first'; + }, + function ($method) { + if (!str_starts_with($method, 'mlp')) { + throw new BadMethodCallException('Try next macro', 0); + } + + return 'local-second'; + }, + ], + ]); + + /** @var mixed $now */ + $now = Carbon::now(); + + $this->assertSame('local-first', $date->mlpSomething()); + $this->assertSame('second', $now->mlpSomething()); + $this->assertSame('second', Carbon::mlpSomething()); + $this->assertSame('mlpFooBar', $date->mlpFooBar()); + $this->assertSame('mlpFooBar', $now->mlpFooBar()); + $this->assertSame('mlpFooBar', Carbon::mlpFooBar()); + } +} diff --git a/tests/CarbonImmutable/IsTest.php b/tests/CarbonImmutable/IsTest.php new file mode 100644 index 0000000..84805d9 --- /dev/null +++ b/tests/CarbonImmutable/IsTest.php @@ -0,0 +1,1163 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Tests\CarbonImmutable; + +use Carbon\CarbonImmutable as Carbon; +use Carbon\CarbonInterval; +use Carbon\Unit; +use DateInterval; +use DateTime; +use InvalidArgumentException; +use PHPUnit\Framework\Attributes\DataProvider; +use stdClass; +use Tests\AbstractTestCase; +use TypeError; + +class IsTest extends AbstractTestCase +{ + public function testIsWeekdayTrue() + { + $this->assertTrue(Carbon::createFromDate(2012, 1, 2)->isWeekday()); + } + + public function testIsWeekdayFalse() + { + $this->assertFalse(Carbon::createFromDate(2012, 1, 1)->isWeekday()); + } + + public function testIsWeekendTrue() + { + $this->assertTrue(Carbon::createFromDate(2012, 1, 1)->isWeekend()); + } + + public function testIsWeekendFalse() + { + $this->assertFalse(Carbon::createFromDate(2012, 1, 2)->isWeekend()); + } + + public function testIsYesterdayTrue() + { + $this->assertTrue(Carbon::now()->subDay()->isYesterday()); + } + + public function testIsYesterdayFalseWithToday() + { + $this->assertFalse(Carbon::now()->endOfDay()->isYesterday()); + } + + public function testIsYesterdayFalseWith2Days() + { + $this->assertFalse(Carbon::now()->subDays(2)->startOfDay()->isYesterday()); + } + + public function testIsTodayTrue() + { + $this->assertTrue(Carbon::now()->isToday()); + } + + public function testIsCurrentWeek() + { + $this->assertFalse(Carbon::now()->subWeek()->isCurrentWeek()); + $this->assertFalse(Carbon::now()->addWeek()->isCurrentWeek()); + $this->assertTrue(Carbon::now()->isCurrentWeek()); + $this->assertTrue(Carbon::now()->startOfWeek()->isCurrentWeek()); + $this->assertTrue(Carbon::now()->endOfWeek()->isCurrentWeek()); + } + + public function testIsSameWeek() + { + $this->assertFalse(Carbon::now()->subWeek()->isSameWeek(Carbon::now())); + $this->assertFalse(Carbon::now()->addWeek()->isSameWeek(Carbon::now())); + $this->assertTrue(Carbon::now()->isSameWeek(Carbon::now())); + $this->assertTrue(Carbon::now()->startOfWeek()->isSameWeek(Carbon::now())); + $this->assertTrue(Carbon::now()->endOfWeek()->isSameWeek(Carbon::now())); + $this->assertTrue(Carbon::parse('2019-01-01')->isSameWeek(Carbon::parse('2018-12-31'))); + } + + public function testIsNextWeekTrue() + { + $this->assertTrue(Carbon::now()->addWeek()->isNextWeek()); + } + + public function testIsLastWeekTrue() + { + $this->assertTrue(Carbon::now()->subWeek()->isLastWeek()); + } + + public function testIsNextWeekFalse() + { + /** @var mixed $date */ + $date = Carbon::now(); + $this->assertFalse($date->addWeek(2)->isNextWeek()); + } + + public function testIsLastWeekFalse() + { + /** @var mixed $date */ + $date = Carbon::now(); + $this->assertFalse($date->subWeek(2)->isLastWeek()); + } + + public function testIsNextQuarterTrue() + { + $this->assertTrue(Carbon::now()->addQuarterNoOverflow()->isNextQuarter()); + } + + public function testIsLastQuarterTrue() + { + $this->assertTrue(Carbon::now()->subQuarterNoOverflow()->isLastQuarter()); + } + + public function testIsNextQuarterFalse() + { + $this->assertFalse(Carbon::now()->addQuartersNoOverflow(2)->isNextQuarter()); + $this->assertFalse(Carbon::now()->addQuartersNoOverflow(5)->isNextQuarter()); + } + + public function testIsLastQuarterFalse() + { + $this->assertFalse(Carbon::now()->subQuartersNoOverflow(2)->isLastQuarter()); + $this->assertFalse(Carbon::now()->subQuartersNoOverflow(5)->isLastQuarter()); + } + + public function testIsNextMonthTrue() + { + $this->assertTrue(Carbon::now()->addMonthNoOverflow()->isNextMonth()); + } + + public function testIsLastMonthTrue() + { + $this->assertTrue(Carbon::now()->subMonthNoOverflow()->isLastMonth()); + } + + public function testIsNextMonthFalse() + { + $this->assertFalse(Carbon::now()->addMonthsNoOverflow(2)->isNextMonth()); + $this->assertFalse(Carbon::now()->addMonthsNoOverflow(13)->isNextMonth()); + } + + public function testIsLastMonthFalse() + { + $this->assertFalse(Carbon::now()->subMonthsNoOverflow(2)->isLastMonth()); + $this->assertFalse(Carbon::now()->subMonthsNoOverflow(13)->isLastMonth()); + } + + public function testIsNextYearTrue() + { + $this->assertTrue(Carbon::now()->addYear()->isNextYear()); + } + + public function testIsLastYearTrue() + { + $this->assertTrue(Carbon::now()->subYear()->isLastYear()); + } + + public function testIsNextYearFalse() + { + /** @var mixed $date */ + $date = Carbon::now(); + $this->assertFalse($date->addYear(2)->isNextYear()); + } + + public function testIsLastYearFalse() + { + /** @var mixed $date */ + $date = Carbon::now(); + $this->assertFalse($date->subYear(2)->isLastYear()); + } + + public function testIsTodayFalseWithYesterday() + { + $this->assertFalse(Carbon::now()->subDay()->endOfDay()->isToday()); + } + + public function testIsTodayFalseWithTomorrow() + { + $this->assertFalse(Carbon::now()->addDay()->startOfDay()->isToday()); + } + + public function testIsTodayWithTimezone() + { + $this->assertTrue(Carbon::now('Asia/Tokyo')->isToday()); + } + + public function testIsTomorrowTrue() + { + $this->assertTrue(Carbon::now()->addDay()->isTomorrow()); + } + + public function testIsTomorrowFalseWithToday() + { + $this->assertFalse(Carbon::now()->endOfDay()->isTomorrow()); + } + + public function testIsTomorrowFalseWith2Days() + { + $this->assertFalse(Carbon::now()->addDays(2)->startOfDay()->isTomorrow()); + } + + public function testIsFutureTrue() + { + $this->assertTrue(Carbon::now()->addSecond()->isFuture()); + } + + public function testIsFutureFalse() + { + $this->assertFalse(Carbon::now()->isFuture()); + } + + public function testIsFutureFalseInThePast() + { + $this->assertFalse(Carbon::now()->subSecond()->isFuture()); + } + + public function testIsPastTrue() + { + $this->assertTrue(Carbon::now()->subSecond()->isPast()); + } + + public function testIsPastFalse() + { + $this->assertFalse(Carbon::now()->addSecond()->isPast()); + } + + public function testNowIsPastFalse() + { + $this->assertFalse(Carbon::now()->isPast()); + } + + public function testIsNowOrFutureTrue() + { + $this->assertTrue(Carbon::now()->addSecond()->isNowOrFuture()); + } + + public function testIsNowOrFutureFalse() + { + $this->assertFalse(Carbon::now()->subSecond()->isNowOrFuture()); + } + + public function testNowIsNowOrFutureTrue() + { + $this->assertTrue(Carbon::now()->isNowOrFuture()); + } + + public function testIsNowOrPastTrue() + { + $this->assertTrue(Carbon::now()->subSecond()->isNowOrPast()); + } + + public function testIsNowOrPastFalse() + { + $this->assertFalse(Carbon::now()->addSecond()->isNowOrPast()); + } + + public function testNowIsNowOrPastTrue() + { + $this->assertTrue(Carbon::now()->isNowOrPast()); + } + + public function testIsLeapYearTrue() + { + $this->assertTrue(Carbon::createFromDate(2016, 1, 1)->isLeapYear()); + } + + public function testIsLeapYearFalse() + { + $this->assertFalse(Carbon::createFromDate(2014, 1, 1)->isLeapYear()); + } + + public function testIsCurrentYearTrue() + { + $this->assertTrue(Carbon::now()->isCurrentYear()); + } + + public function testIsCurrentYearFalse() + { + $this->assertFalse(Carbon::now()->subYear()->isCurrentYear()); + } + + public function testIsSameYearTrue() + { + $this->assertTrue(Carbon::now()->isSameYear(Carbon::now())); + } + + public function testIsSameYearFalse() + { + $this->assertFalse(Carbon::now()->isSameYear(Carbon::now()->subYear())); + } + + public function testIsCurrentDecadeTrue() + { + $this->assertTrue(Carbon::now()->isCurrentDecade()); + } + + public function testIsCurrentDecadeFalse() + { + $this->assertFalse(Carbon::now()->subDecade()->isCurrentDecade()); + } + + public function testIsSameDecadeTrue() + { + $this->assertTrue(Carbon::now()->isSameDecade(Carbon::now())); + $this->assertTrue(Carbon::now()->isSameUnit('millennium', Carbon::now())); + } + + public function testIsSameDecadeFalse() + { + $this->assertFalse(Carbon::now()->isSameDecade(Carbon::now()->subDecade())); + $this->assertFalse(Carbon::now()->isSameUnit('millennium', Carbon::now()->subMillennia(2))); + } + + public function testIsSameFoobar() + { + $this->expectExceptionObject(new InvalidArgumentException( + 'Bad comparison unit: \'foobar\'', + )); + + Carbon::now()->isSameUnit('foobar', Carbon::now()->subMillennium()); + } + + public function testIsCurrentQuarterTrue() + { + $this->assertTrue(Carbon::now()->isCurrentQuarter()); + } + + public function testIsCurrentQuarterFalse() + { + Carbon::useMonthsOverflow(false); + $this->assertFalse(Carbon::now()->subQuarter()->isCurrentQuarter()); + Carbon::resetMonthsOverflow(); + } + + public function testIsSameQuarterTrue() + { + $this->assertTrue(Carbon::now()->isSameQuarter(Carbon::now())); + } + + public function testIsSameQuarterTrueWithDateTime() + { + $this->assertTrue(Carbon::now()->isSameQuarter(new DateTime())); + } + + public function testIsSameQuarterFalse() + { + Carbon::useMonthsOverflow(false); + $this->assertFalse(Carbon::now()->isSameQuarter(Carbon::now()->subQuarter())); + Carbon::resetMonthsOverflow(); + } + + public function testIsSameQuarterFalseWithDateTime() + { + $now = Carbon::now(); + $dt = new DateTime(); + $dt->modify((Carbon::MONTHS_PER_QUARTER * -1).' month'); + + if ($dt->format('d') !== $now->format('d')) { + $dt->modify('last day of previous month'); + } + + $this->assertFalse($now->isSameQuarter($dt)); + } + + public function testIsSameQuarterAndYearTrue() + { + $this->assertTrue(Carbon::now()->isSameQuarter(Carbon::now(), true)); + } + + public function testIsSameQuarterAndYearTrueWithDateTime() + { + $this->assertTrue(Carbon::now()->isSameQuarter(new DateTime(), true)); + } + + public function testIsSameQuarterAndYearFalse() + { + $this->assertFalse(Carbon::now()->isSameQuarter(Carbon::now()->subYear(), true)); + } + + public function testIsSameQuarterAndYearFalseWithDateTime() + { + $dt = new DateTime(); + $dt->modify('-1 year'); + $this->assertFalse(Carbon::now()->isSameQuarter($dt, true)); + } + + public function testIsCurrentMonth() + { + $this->assertTrue(Carbon::now()->isCurrentMonth()); + $dt = Carbon::now(); + $dt = $dt->modify(Carbon::now()->year.$dt->format('-m-').'01'); + $this->assertTrue($dt->isCurrentMonth()); + $dt = $dt->modify((Carbon::now()->year + 1).$dt->format('-m-').'28'); + $this->assertFalse($dt->isCurrentMonth()); + } + + public function testIsCurrentMonthFalse() + { + $this->assertFalse(Carbon::now()->day(15)->subMonth()->isCurrentMonth()); + $this->assertFalse(Carbon::now()->day(15)->addYear()->isCurrentMonth()); + } + + public function testIsSameMonth() + { + $this->assertTrue(Carbon::now()->isSameMonth(Carbon::now())); + $dt = Carbon::now(); + for ($year = 1990; $year < Carbon::now()->year; $year++) { + $dt->modify($year.$dt->format('-m-').'01'); + $this->assertTrue(Carbon::now()->isSameMonth($dt, false)); + $dt->modify($year.$dt->format('-m-').'28'); + $this->assertTrue(Carbon::now()->isSameMonth($dt, false)); + } + } + + public function testIsSameMonthTrueWithDateTime() + { + $this->assertTrue(Carbon::now()->isSameMonth(new DateTime())); + $dt = new DateTime(); + for ($year = 1990; $year < 2200; $year++) { + $dt->modify($year.$dt->format('-m-').'01'); + $this->assertTrue(Carbon::now()->isSameMonth($dt, false)); + $dt->modify($year.$dt->format('-m-').'28'); + $this->assertTrue(Carbon::now()->isSameMonth($dt, false)); + } + } + + public function testIsSameMonthOfSameYear() + { + $this->assertFalse(Carbon::now()->isSameMonth(Carbon::now()->day(15)->subMonth())); + $this->assertTrue(Carbon::now()->isSameMonth(Carbon::now())); + $dt = Carbon::now(); + for ($year = 1990; $year < Carbon::now()->year; $year++) { + $dt = $dt->modify($year.$dt->format('-m-').'01'); + $this->assertFalse(Carbon::now()->isSameMonth($dt, true)); + $dt = $dt->modify($year.$dt->format('-m-').'28'); + $this->assertFalse(Carbon::now()->isSameMonth($dt, true)); + } + $year = Carbon::now()->year; + $dt = $dt->modify($year.$dt->format('-m-').'01'); + $this->assertTrue(Carbon::now()->isSameMonth($dt, true)); + $dt = $dt->modify($year.$dt->format('-m-').'28'); + $this->assertTrue(Carbon::now()->isSameMonth($dt, true)); + for ($year = Carbon::now()->year + 1; $year < 2200; $year++) { + $dt = $dt->modify($year.$dt->format('-m-').'01'); + $this->assertFalse(Carbon::now()->isSameMonth($dt, true)); + $dt = $dt->modify($year.$dt->format('-m-').'28'); + $this->assertFalse(Carbon::now()->isSameMonth($dt, true)); + } + } + + public function testIsSameMonthFalseWithDateTime() + { + $dt = new DateTime(); + $dt = $dt->modify('-2 month'); + $this->assertFalse(Carbon::now()->isSameMonth($dt)); + } + + public function testIsSameMonthAndYearTrue() + { + $this->assertTrue(Carbon::now()->isSameMonth(Carbon::now(), true)); + $dt = Carbon::now(); + $dt = $dt->modify($dt->format('Y-m-').'01'); + $this->assertTrue(Carbon::now()->isSameMonth($dt, true)); + $dt = $dt->modify($dt->format('Y-m-').'28'); + $this->assertTrue(Carbon::now()->isSameMonth($dt, true)); + } + + public function testIsSameMonthAndYearTrueWithDateTime() + { + $this->assertTrue(Carbon::now()->isSameMonth(new DateTime(), true)); + $dt = new DateTime(); + $dt = $dt->modify($dt->format('Y-m-').'01'); + $this->assertTrue(Carbon::now()->isSameMonth($dt, true)); + $dt = $dt->modify($dt->format('Y-m-').'28'); + $this->assertTrue(Carbon::now()->isSameMonth($dt, true)); + } + + public function testIsSameMonthAndYearFalse() + { + $this->assertFalse(Carbon::now()->isSameMonth(Carbon::now()->subYear(), true)); + } + + public function testIsSameMonthAndYearFalseWithDateTime() + { + $dt = new DateTime(); + $dt = $dt->modify('-1 year'); + $this->assertFalse(Carbon::now()->isSameMonth($dt, true)); + } + + public function testIsSameDayTrue() + { + $current = Carbon::createFromDate(2012, 1, 2); + $this->assertTrue($current->isSameDay(Carbon::createFromDate(2012, 1, 2))); + $this->assertTrue($current->isSameDay(Carbon::create(2012, 1, 2, 23, 59, 59))); + } + + public function testIsSameDayWithString() + { + $current = Carbon::createFromDate(2012, 1, 2); + $this->assertTrue($current->isSameDay('2012-01-02 15:00:25')); + $this->assertTrue($current->isSameDay('2012-01-02')); + } + + public function testIsSameDayTrueWithDateTime() + { + $current = Carbon::createFromDate(2012, 1, 2); + $this->assertTrue($current->isSameDay(new DateTime('2012-01-02'))); + $this->assertTrue($current->isSameDay(new DateTime('2012-01-02 23:59:59'))); + } + + public function testIsSameDayFalse() + { + $current = Carbon::createFromDate(2012, 1, 2); + $this->assertFalse($current->isSameDay(Carbon::createFromDate(2012, 1, 3))); + $this->assertFalse($current->isSameDay(Carbon::createFromDate(2012, 6, 2))); + } + + public function testIsSameDayFalseWithDateTime() + { + $current = Carbon::createFromDate(2012, 1, 2); + $this->assertFalse($current->isSameDay(new DateTime('2012-01-03'))); + $this->assertFalse($current->isSameDay(new DateTime('2012-05-02'))); + } + + public function testIsCurrentDayTrue() + { + $this->assertTrue(Carbon::now()->isCurrentDay()); + $this->assertTrue(Carbon::now()->hour(0)->isCurrentDay()); + $this->assertTrue(Carbon::now()->hour(23)->isCurrentDay()); + } + + public function testIsCurrentDayFalse() + { + $this->assertFalse(Carbon::now()->subDay()->isCurrentDay()); + $this->assertFalse(Carbon::now()->subMonth()->isCurrentDay()); + } + + public function testIsSameHourTrue() + { + $current = Carbon::create(2018, 5, 6, 12); + $this->assertTrue($current->isSameHour(Carbon::create(2018, 5, 6, 12))); + $this->assertTrue($current->isSameHour(Carbon::create(2018, 5, 6, 12, 59, 59))); + } + + public function testIsSameHourTrueWithDateTime() + { + $current = Carbon::create(2018, 5, 6, 12); + $this->assertTrue($current->isSameHour(new DateTime('2018-05-06T12:00:00'))); + $this->assertTrue($current->isSameHour(new DateTime('2018-05-06T12:59:59'))); + } + + public function testIsSameHourFalse() + { + $current = Carbon::create(2018, 5, 6, 12); + $this->assertFalse($current->isSameHour(Carbon::create(2018, 5, 6, 13))); + $this->assertFalse($current->isSameHour(Carbon::create(2018, 5, 5, 12))); + } + + public function testIsSameHourFalseWithDateTime() + { + $current = Carbon::create(2018, 5, 6, 12); + $this->assertFalse($current->isSameHour(new DateTime('2018-05-06T13:00:00'))); + $this->assertFalse($current->isSameHour(new DateTime('2018-06-06T12:00:00'))); + } + + public function testIsCurrentHourTrue() + { + $this->assertTrue(Carbon::now()->isCurrentHour()); + $this->assertTrue(Carbon::now()->second(1)->isCurrentHour()); + $this->assertTrue(Carbon::now()->second(12)->isCurrentHour()); + $this->assertTrue(Carbon::now()->minute(0)->isCurrentHour()); + $this->assertTrue(Carbon::now()->minute(59)->second(59)->isCurrentHour()); + } + + public function testIsCurrentHourFalse() + { + $this->assertFalse(Carbon::now()->subHour()->isCurrentHour()); + $this->assertFalse(Carbon::now()->subDay()->isCurrentHour()); + } + + public function testIsSameMinuteTrue() + { + $current = Carbon::create(2018, 5, 6, 12, 30); + $this->assertTrue($current->isSameMinute(Carbon::create(2018, 5, 6, 12, 30))); + $current = Carbon::create(2018, 5, 6, 12, 30, 15); + $this->assertTrue($current->isSameMinute(Carbon::create(2018, 5, 6, 12, 30, 45))); + } + + public function testIsSameMinuteTrueWithDateTime() + { + $current = Carbon::create(2018, 5, 6, 12, 30); + $this->assertTrue($current->isSameMinute(new DateTime('2018-05-06T12:30:00'))); + $current = Carbon::create(2018, 5, 6, 12, 30, 20); + $this->assertTrue($current->isSameMinute(new DateTime('2018-05-06T12:30:40'))); + } + + public function testIsSameMinuteFalse() + { + $current = Carbon::create(2018, 5, 6, 12, 30); + $this->assertFalse($current->isSameMinute(Carbon::create(2018, 5, 6, 13, 31))); + $this->assertFalse($current->isSameMinute(Carbon::create(2019, 5, 6, 13, 30))); + } + + public function testIsSameMinuteFalseWithDateTime() + { + $current = Carbon::create(2018, 5, 6, 12, 30); + $this->assertFalse($current->isSameMinute(new DateTime('2018-05-06T13:31:00'))); + $this->assertFalse($current->isSameMinute(new DateTime('2018-05-06T17:30:00'))); + } + + public function testIsCurrentMinuteTrue() + { + $this->assertTrue(Carbon::now()->isCurrentMinute()); + $this->assertTrue(Carbon::now()->second(0)->isCurrentMinute()); + $this->assertTrue(Carbon::now()->second(59)->isCurrentMinute()); + } + + public function testIsCurrentMinuteFalse() + { + $this->assertFalse(Carbon::now()->subMinute()->isCurrentMinute()); + $this->assertFalse(Carbon::now()->subHour()->isCurrentMinute()); + } + + public function testIsSameSecondTrue() + { + $current = Carbon::create(2018, 5, 6, 12, 30, 13); + $other = Carbon::create(2018, 5, 6, 12, 30, 13); + $this->assertTrue($current->isSameSecond($other)); + $this->assertTrue($current->modify($current->hour.':'.$current->minute.':'.$current->second.'.0')->isSameSecond($other)); + $this->assertTrue($current->modify($current->hour.':'.$current->minute.':'.$current->second.'.999999')->isSameSecond($other)); + } + + public function testIsSameSecondTrueWithDateTime() + { + $current = Carbon::create(2018, 5, 6, 12, 30, 13); + $this->assertTrue($current->isSameSecond(new DateTime('2018-05-06T12:30:13'))); + } + + public function testIsSameSecondFalse() + { + $current = Carbon::create(2018, 5, 6, 12, 30, 13); + $this->assertFalse($current->isSameSecond(Carbon::create(2018, 5, 6, 12, 30, 55))); + $this->assertFalse($current->isSameSecond(Carbon::create(2018, 5, 6, 14, 30, 13))); + } + + public function testIsSameSecondFalseWithDateTime() + { + $current = Carbon::create(2018, 5, 6, 12, 30, 13); + $this->assertFalse($current->isSameSecond(new DateTime('2018-05-06T13:30:54'))); + $this->assertFalse($current->isSameSecond(new DateTime('2018-05-06T13:36:13'))); + } + + public function testIsCurrentSecondTrue() + { + $this->assertTrue(Carbon::now()->isCurrentSecond()); + $now = Carbon::now(); + $this->assertTrue($now->modify($now->hour.':'.$now->minute.':'.$now->second.'.0')->isCurrentSecond()); + $this->assertTrue($now->modify($now->hour.':'.$now->minute.':'.$now->second.'.999999')->isCurrentSecond()); + } + + public function testIsCurrentSecondFalse() + { + $this->assertFalse(Carbon::now()->subSecond()->isCurrentSecond()); + $this->assertFalse(Carbon::now()->subDay()->isCurrentSecond()); + } + + public function testIsSameMicrosecond() + { + $current = new Carbon('2018-05-06T13:30:54.123456'); + $this->assertTrue($current->isSameMicrosecond(new DateTime('2018-05-06T13:30:54.123456'))); + $this->assertFalse($current->isSameMicrosecond(new DateTime('2018-05-06T13:30:54.123457'))); + $this->assertFalse($current->isSameMicrosecond(new DateTime('2019-05-06T13:30:54.123456'))); + $this->assertFalse($current->isSameMicrosecond(new DateTime('2018-05-06T13:30:55.123456'))); + $this->assertTrue($current->isSameSecond($current->copy())); + $this->assertTrue(Carbon::now()->isCurrentMicrosecond()); + $this->assertFalse(Carbon::now()->subMicrosecond()->isCurrentMicrosecond()); + $this->assertFalse(Carbon::now()->isLastMicrosecond()); + $this->assertTrue(Carbon::now()->subMicrosecond()->isLastMicrosecond()); + $this->assertFalse(Carbon::now()->isNextMicrosecond()); + $this->assertTrue(Carbon::now()->addMicrosecond()->isNextMicrosecond()); + $this->assertTrue(Carbon::now()->subMicroseconds(Carbon::MICROSECONDS_PER_SECOND)->isLastSecond()); + $this->assertSame(4.0, Carbon::now()->subMicroseconds(4 * Carbon::MICROSECONDS_PER_SECOND)->diffInSeconds(Carbon::now())); + } + + public function testIsDayOfWeek() + { + // True in the past past + $this->assertTrue(Carbon::createFromDate(2015, 5, 31)->isDayOfWeek(0)); + $this->assertTrue(Carbon::createFromDate(2015, 6, 21)->isDayOfWeek(0)); + $this->assertTrue(Carbon::now()->subWeek()->previous(Carbon::SUNDAY)->isDayOfWeek(0)); + $this->assertTrue(Carbon::now()->subWeek()->previous(Carbon::SUNDAY)->isDayOfWeek('sunday')); + $this->assertTrue(Carbon::now()->subWeek()->previous(Carbon::SUNDAY)->isDayOfWeek('SUNDAY')); + + // True in the future + $this->assertTrue(Carbon::now()->addWeek()->previous(Carbon::SUNDAY)->isDayOfWeek(0)); + $this->assertTrue(Carbon::now()->addMonth()->previous(Carbon::SUNDAY)->isDayOfWeek(0)); + $this->assertTrue(Carbon::now()->addMonth()->previous(Carbon::SUNDAY)->isDayOfWeek('sunday')); + $this->assertTrue(Carbon::now()->addMonth()->previous(Carbon::SUNDAY)->isDayOfWeek('SUNDAY')); + $this->assertTrue(Carbon::now()->addMonth()->previous(Carbon::MONDAY)->isDayOfWeek('monday')); + $this->assertTrue(Carbon::now()->addMonth()->previous(Carbon::MONDAY)->isDayOfWeek('MONDAY')); + + // False in the past + $this->assertFalse(Carbon::now()->subWeek()->previous(Carbon::MONDAY)->isDayOfWeek(0)); + $this->assertFalse(Carbon::now()->subMonth()->previous(Carbon::MONDAY)->isDayOfWeek(0)); + $this->assertFalse(Carbon::now()->subMonth()->previous(Carbon::MONDAY)->isDayOfWeek('sunday')); + $this->assertFalse(Carbon::now()->subMonth()->previous(Carbon::MONDAY)->isDayOfWeek('SUNDAY')); + $this->assertFalse(Carbon::now()->subMonth()->previous(Carbon::SUNDAY)->isDayOfWeek('monday')); + $this->assertFalse(Carbon::now()->subMonth()->previous(Carbon::SUNDAY)->isDayOfWeek('MONDAY')); + + // False in the future + $this->assertFalse(Carbon::now()->addWeek()->previous(Carbon::MONDAY)->isDayOfWeek(0)); + $this->assertFalse(Carbon::now()->addMonth()->previous(Carbon::MONDAY)->isDayOfWeek(0)); + $this->assertFalse(Carbon::now()->addMonth()->previous(Carbon::MONDAY)->isDayOfWeek('sunday')); + $this->assertFalse(Carbon::now()->addMonth()->previous(Carbon::MONDAY)->isDayOfWeek('SUNDAY')); + $this->assertFalse(Carbon::now()->addMonth()->previous(Carbon::SUNDAY)->isDayOfWeek('monday')); + $this->assertFalse(Carbon::now()->addMonth()->previous(Carbon::SUNDAY)->isDayOfWeek('MONDAY')); + } + + public function testIsSameAs() + { + $current = Carbon::createFromDate(2012, 1, 2); + $this->assertTrue($current->isSameAs('c', $current)); + } + + public function testIsSameAsWithInvalidArgument() + { + $this->expectException(TypeError::class); + + $current = Carbon::createFromDate(2012, 1, 2); + $current->isSameAs('Y-m-d', new stdClass()); + } + + public function testIsSunday() + { + // True in the past past + $this->assertTrue(Carbon::createFromDate(2015, 5, 31)->isSunday()); + $this->assertTrue(Carbon::createFromDate(2015, 6, 21)->isSunday()); + $this->assertTrue(Carbon::now()->subWeek()->previous(Carbon::SUNDAY)->isSunday()); + + // True in the future + $this->assertTrue(Carbon::now()->addWeek()->previous(Carbon::SUNDAY)->isSunday()); + $this->assertTrue(Carbon::now()->addMonth()->previous(Carbon::SUNDAY)->isSunday()); + + // False in the past + $this->assertFalse(Carbon::now()->subWeek()->previous(Carbon::MONDAY)->isSunday()); + $this->assertFalse(Carbon::now()->subMonth()->previous(Carbon::MONDAY)->isSunday()); + + // False in the future + $this->assertFalse(Carbon::now()->addWeek()->previous(Carbon::MONDAY)->isSunday()); + $this->assertFalse(Carbon::now()->addMonth()->previous(Carbon::MONDAY)->isSunday()); + } + + public function testIsMonday() + { + // True in the past past + $this->assertTrue(Carbon::createFromDate(2015, 6, 1)->isMonday()); + $this->assertTrue(Carbon::now()->subWeek()->previous(Carbon::MONDAY)->isMonday()); + + // True in the future + $this->assertTrue(Carbon::now()->addWeek()->previous(Carbon::MONDAY)->isMonday()); + $this->assertTrue(Carbon::now()->addMonth()->previous(Carbon::MONDAY)->isMonday()); + + // False in the past + $this->assertFalse(Carbon::now()->subWeek()->previous(Carbon::TUESDAY)->isMonday()); + $this->assertFalse(Carbon::now()->subMonth()->previous(Carbon::TUESDAY)->isMonday()); + + // False in the future + $this->assertFalse(Carbon::now()->addWeek()->previous(Carbon::TUESDAY)->isMonday()); + $this->assertFalse(Carbon::now()->addMonth()->previous(Carbon::TUESDAY)->isMonday()); + } + + public function testIsTuesday() + { + // True in the past past + $this->assertTrue(Carbon::createFromDate(2015, 6, 2)->isTuesday()); + $this->assertTrue(Carbon::now()->subWeek()->previous(Carbon::TUESDAY)->isTuesday()); + + // True in the future + $this->assertTrue(Carbon::now()->addWeek()->previous(Carbon::TUESDAY)->isTuesday()); + $this->assertTrue(Carbon::now()->addMonth()->previous(Carbon::TUESDAY)->isTuesday()); + + // False in the past + $this->assertFalse(Carbon::now()->subWeek()->previous(Carbon::WEDNESDAY)->isTuesday()); + $this->assertFalse(Carbon::now()->subMonth()->previous(Carbon::WEDNESDAY)->isTuesday()); + + // False in the future + $this->assertFalse(Carbon::now()->addWeek()->previous(Carbon::WEDNESDAY)->isTuesday()); + $this->assertFalse(Carbon::now()->addMonth()->previous(Carbon::WEDNESDAY)->isTuesday()); + } + + public function testIsWednesday() + { + // True in the past past + $this->assertTrue(Carbon::createFromDate(2015, 6, 3)->isWednesday()); + $this->assertTrue(Carbon::now()->subWeek()->previous(Carbon::WEDNESDAY)->isWednesday()); + + // True in the future + $this->assertTrue(Carbon::now()->addWeek()->previous(Carbon::WEDNESDAY)->isWednesday()); + $this->assertTrue(Carbon::now()->addMonth()->previous(Carbon::WEDNESDAY)->isWednesday()); + + // False in the past + $this->assertFalse(Carbon::now()->subWeek()->previous(Carbon::THURSDAY)->isWednesday()); + $this->assertFalse(Carbon::now()->subMonth()->previous(Carbon::THURSDAY)->isWednesday()); + + // False in the future + $this->assertFalse(Carbon::now()->addWeek()->previous(Carbon::THURSDAY)->isWednesday()); + $this->assertFalse(Carbon::now()->addMonth()->previous(Carbon::THURSDAY)->isWednesday()); + } + + public function testIsThursday() + { + // True in the past past + $this->assertTrue(Carbon::createFromDate(2015, 6, 4)->isThursday()); + $this->assertTrue(Carbon::now()->subWeek()->previous(Carbon::THURSDAY)->isThursday()); + + // True in the future + $this->assertTrue(Carbon::now()->addWeek()->previous(Carbon::THURSDAY)->isThursday()); + $this->assertTrue(Carbon::now()->addMonth()->previous(Carbon::THURSDAY)->isThursday()); + + // False in the past + $this->assertFalse(Carbon::now()->subWeek()->previous(Carbon::FRIDAY)->isThursday()); + $this->assertFalse(Carbon::now()->subMonth()->previous(Carbon::FRIDAY)->isThursday()); + + // False in the future + $this->assertFalse(Carbon::now()->addWeek()->previous(Carbon::FRIDAY)->isThursday()); + $this->assertFalse(Carbon::now()->addMonth()->previous(Carbon::FRIDAY)->isThursday()); + } + + public function testIsFriday() + { + // True in the past past + $this->assertTrue(Carbon::createFromDate(2015, 6, 5)->isFriday()); + $this->assertTrue(Carbon::now()->subWeek()->previous(Carbon::FRIDAY)->isFriday()); + + // True in the future + $this->assertTrue(Carbon::now()->addWeek()->previous(Carbon::FRIDAY)->isFriday()); + $this->assertTrue(Carbon::now()->addMonth()->previous(Carbon::FRIDAY)->isFriday()); + + // False in the past + $this->assertFalse(Carbon::now()->subWeek()->previous(Carbon::SATURDAY)->isFriday()); + $this->assertFalse(Carbon::now()->subMonth()->previous(Carbon::SATURDAY)->isFriday()); + + // False in the future + $this->assertFalse(Carbon::now()->addWeek()->previous(Carbon::SATURDAY)->isFriday()); + $this->assertFalse(Carbon::now()->addMonth()->previous(Carbon::SATURDAY)->isFriday()); + } + + public function testIsSaturday() + { + // True in the past past + $this->assertTrue(Carbon::createFromDate(2015, 6, 6)->isSaturday()); + $this->assertTrue(Carbon::now()->subWeek()->previous(Carbon::SATURDAY)->isSaturday()); + + // True in the future + $this->assertTrue(Carbon::now()->addWeek()->previous(Carbon::SATURDAY)->isSaturday()); + $this->assertTrue(Carbon::now()->addMonth()->previous(Carbon::SATURDAY)->isSaturday()); + + // False in the past + $this->assertFalse(Carbon::now()->subWeek()->previous(Carbon::SUNDAY)->isSaturday()); + $this->assertFalse(Carbon::now()->subMonth()->previous(Carbon::SUNDAY)->isSaturday()); + + // False in the future + $this->assertFalse(Carbon::now()->addWeek()->previous(Carbon::SUNDAY)->isSaturday()); + $this->assertFalse(Carbon::now()->addMonth()->previous(Carbon::SUNDAY)->isSaturday()); + } + + public function testIsStartOfDay() + { + $this->assertTrue(Carbon::parse('00:00:00')->isStartOfDay(false)); + $this->assertTrue(Carbon::parse('00:00:00.999999')->isStartOfDay(false)); + $this->assertTrue(Carbon::now()->startOfDay()->isStartOfDay(false)); + + $this->assertFalse(Carbon::parse('15:30:45')->isStartOfDay(false)); + $this->assertFalse(Carbon::now()->endOfDay()->isStartOfDay(false)); + + $this->assertTrue(Carbon::parse('00:00:00')->isStartOfDay()); + $this->assertTrue(Carbon::parse('00:00:00.999999')->isStartOfDay()); + $this->assertTrue(Carbon::now()->startOfDay()->isStartOfDay()); + + $this->assertFalse(Carbon::parse('15:30:45')->isStartOfDay()); + $this->assertFalse(Carbon::now()->endOfDay()->isStartOfDay()); + } + + public function testIsStartOfDayInterval() + { + $this->assertTrue(Carbon::parse('00:00:00')->isStartOfDay('15 minutes')); + $this->assertTrue(Carbon::parse('00:14:59.999999')->isStartOfDay('15 minutes')); + $this->assertFalse(Carbon::parse('00:15:00')->isStartOfDay('15 minutes')); + $this->assertTrue(Carbon::parse('00:59:59.999999')->isStartOfDay(Unit::Hour)); + $this->assertFalse(Carbon::parse('01:00:00')->isStartOfDay(Unit::Hour)); + $this->assertTrue(Carbon::parse('00:00:59.999999')->isStartOfDay(new DateInterval('PT1M'))); + $this->assertFalse(Carbon::parse('00:01:00')->isStartOfDay(new DateInterval('PT1M'))); + + $this->assertTrue(Carbon::parse('00:00:00')->isStartOfDay(interval: '15 minutes')); + $this->assertTrue(Carbon::parse('00:14:59.999999')->isStartOfDay(interval: '15 minutes')); + $this->assertFalse(Carbon::parse('00:15:00')->isStartOfDay(interval: '15 minutes')); + $this->assertTrue(Carbon::parse('00:59:59.999999')->isStartOfDay(interval: Unit::Hour)); + $this->assertFalse(Carbon::parse('01:00:00')->isStartOfDay(interval: Unit::Hour)); + $this->assertTrue(Carbon::parse('00:00:59.999999')->isStartOfDay(interval: new DateInterval('PT1M'))); + $this->assertFalse(Carbon::parse('00:01:00')->isStartOfDay(interval: new DateInterval('PT1M'))); + + $this->assertTrue(Carbon::parse('00:01:59.999999')->isStartOfDay(interval: CarbonInterval::minutes(2))); + $this->assertFalse(Carbon::parse('00:02:00')->isStartOfDay(interval: CarbonInterval::minutes(2))); + + // Always false with negative interval + $this->assertFalse(Carbon::parse('00:00:00')->isStartOfDay(interval: CarbonInterval::minutes(-2))); + + // Always true with interval bigger than 1 day + $this->assertTrue(Carbon::parse('23:59:59.999999')->isStartOfDay(interval: CarbonInterval::hours(36))); + } + + public function testIsStartOfUnit() + { + $this->assertTrue(Carbon::parse('00:00:00')->isStartOfUnit(Unit::Hour)); + + $this->assertFalse(Carbon::parse('00:00:00.000001')->isStartOfUnit(Unit::Hour)); + $this->assertFalse(Carbon::parse('00:00:01')->isStartOfUnit(Unit::Hour)); + + $this->assertTrue(Carbon::parse('00:00:00')->isStartOfUnit(Unit::Hour, '5 minutes')); + $this->assertTrue(Carbon::parse('00:04:59.999999')->isStartOfUnit(Unit::Hour, '5 minutes')); + + $this->assertFalse(Carbon::parse('00:05:00')->isStartOfUnit(Unit::Hour, '5 minutes')); + + $this->assertTrue(Carbon::parse('Monday')->isStartOfUnit(Unit::Week)); + $this->assertTrue(Carbon::parse('Monday 23:59:59.999999')->isStartOfUnit(Unit::Week)); + + $this->assertFalse(Carbon::parse('Tuesday')->isStartOfUnit(Unit::Week)); + $this->assertFalse(Carbon::parse('Monday')->isStartOfUnit(Unit::Week, CarbonInterval::day(-1))); + } + + public function testIsStartOfDayWithMicroseconds() + { + $this->assertTrue(Carbon::parse('00:00:00')->isStartOfDay(true)); + $this->assertTrue(Carbon::now()->startOfDay()->isStartOfDay(true)); + + $this->assertFalse(Carbon::parse('00:00:00.000001')->isStartOfDay(true)); + } + + public function testIsEndOfDay() + { + $this->assertTrue(Carbon::parse('23:59:59')->isEndOfDay(false)); + $this->assertTrue(Carbon::parse('23:59:59.000000')->isEndOfDay(false)); + $this->assertTrue(Carbon::now()->endOfDay()->isEndOfDay(false)); + + $this->assertFalse(Carbon::parse('15:30:45')->isEndOfDay(false)); + $this->assertFalse(Carbon::now()->startOfDay()->isEndOfDay(false)); + + $this->assertTrue(Carbon::parse('23:59:59')->isEndOfDay()); + $this->assertTrue(Carbon::parse('23:59:59.000000')->isEndOfDay()); + $this->assertTrue(Carbon::now()->endOfDay()->isEndOfDay()); + + $this->assertFalse(Carbon::parse('15:30:45')->isEndOfDay()); + $this->assertFalse(Carbon::now()->startOfDay()->isEndOfDay()); + } + + public function testIsEndOfDayInterval() + { + $this->assertTrue(Carbon::parse('23:59:59.999999')->isEndOfDay('15 minutes')); + $this->assertTrue(Carbon::parse('23:45:00')->isEndOfDay('15 minutes')); + $this->assertFalse(Carbon::parse('23:44:59.999999')->isEndOfDay('15 minutes')); + $this->assertTrue(Carbon::parse('23:00:00')->isEndOfDay(Unit::Hour)); + $this->assertFalse(Carbon::parse('22:59:59.999999')->isEndOfDay(Unit::Hour)); + $this->assertTrue(Carbon::parse('23:59:00')->isEndOfDay(new DateInterval('PT1M'))); + $this->assertFalse(Carbon::parse('23:58:59.999999')->isEndOfDay(new DateInterval('PT1M'))); + + $this->assertTrue(Carbon::parse('23:59:59.999999')->isEndOfDay(interval: '15 minutes')); + $this->assertTrue(Carbon::parse('23:45:00')->isEndOfDay(interval: '15 minutes')); + $this->assertFalse(Carbon::parse('23:44:59.999999')->isEndOfDay(interval: '15 minutes')); + $this->assertTrue(Carbon::parse('23:00:00')->isEndOfDay(interval: Unit::Hour)); + $this->assertFalse(Carbon::parse('22:59:59.999999')->isEndOfDay(interval: Unit::Hour)); + $this->assertTrue(Carbon::parse('23:59:00')->isEndOfDay(interval: new DateInterval('PT1M'))); + $this->assertFalse(Carbon::parse('23:58:59.999999')->isEndOfDay(interval: new DateInterval('PT1M'))); + + // Always false with negative interval + $this->assertFalse(Carbon::parse('00:00:00')->isEndOfDay(interval: CarbonInterval::minutes(-2))); + + // Always true with interval bigger than 1 day + $this->assertTrue(Carbon::parse('23:59:59.999999')->isEndOfDay(interval: CarbonInterval::hours(36))); + } + + public function testIsEndOfDayWithMicroseconds() + { + $this->assertTrue(Carbon::parse('23:59:59.999999')->isEndOfDay(true)); + $this->assertTrue(Carbon::now()->endOfDay()->isEndOfDay(true)); + + $this->assertFalse(Carbon::parse('23:59:59')->isEndOfDay(true)); + $this->assertFalse(Carbon::parse('23:59:59.999998')->isEndOfDay(true)); + } + + public function testIsEndOfUnit() + { + $this->assertTrue(Carbon::parse('23:59:59.999999')->isEndOfUnit(Unit::Hour)); + + $this->assertFalse(Carbon::parse('23:59:59.999998')->isEndOfUnit(Unit::Hour)); + $this->assertFalse(Carbon::parse('23:59:59')->isEndOfUnit(Unit::Hour)); + + $this->assertTrue(Carbon::parse('23:55:00.000001')->isEndOfUnit(Unit::Hour, '5 minutes')); + $this->assertTrue(Carbon::parse('23:55:00')->isEndOfUnit(Unit::Hour, '5 minutes')); + + $this->assertFalse(Carbon::parse('23:54:59.999999')->isEndOfUnit(Unit::Hour, '5 minutes')); + + $this->assertTrue(Carbon::parse('Sunday 23:59:59')->isEndOfUnit(Unit::Week, '2 days')); + $this->assertTrue(Carbon::parse('Saturday 00:00')->isEndOfUnit(Unit::Week, '2 days')); + + $this->assertFalse(Carbon::parse('Saturday 00:00')->isEndOfUnit(Unit::Week)); + $this->assertFalse(Carbon::parse('Friday 23:59:59.999999')->isEndOfUnit(Unit::Week, '2 days')); + $this->assertFalse(Carbon::parse('Sunday 23:59:59.999999')->isEndOfUnit(Unit::Week, CarbonInterval::day(-1))); + } + + public function testIsMidnight() + { + $this->assertTrue(Carbon::parse('00:00:00')->isMidnight()); + + $this->assertFalse(Carbon::parse('15:30:45')->isMidnight()); + } + + public function testIsMidday() + { + $this->assertTrue(Carbon::parse('12:00:00')->isMidday()); + + $this->assertFalse(Carbon::parse('15:30:45')->isMidday()); + } + + public function testHasFormat() + { + $this->assertTrue(Carbon::hasFormat('1975-05-01', 'Y-m-d')); + $this->assertTrue(Carbon::hasFormat('12/30/2019', 'm/d/Y')); + $this->assertTrue(Carbon::hasFormat('30/12/2019', 'd/m/Y')); + $this->assertTrue(Carbon::hasFormat('Sun 21st', 'D jS')); + + $this->assertTrue(Carbon::hasFormat('2000-07-01T00:00:00+00:00', DateTime::ATOM)); + $this->assertTrue(Carbon::hasFormat('Y-01-30\\', '\\Y-m-d\\\\')); + + // @see https://github.com/briannesbitt/Carbon/issues/2180 + $this->assertTrue(Carbon::hasFormat('2020-09-01 12:00:00Europe/Moscow', 'Y-m-d H:i:se')); + + $this->assertTrue(Carbon::hasFormat('2012-12-04 22:59.32130', 'Y-m-d H:s.vi')); + + // Format failure + $this->assertFalse(Carbon::hasFormat('', 'd m Y')); + $this->assertFalse(Carbon::hasFormat('1975-05-01', 'd m Y')); + $this->assertFalse(Carbon::hasFormat('Foo 21st', 'D jS')); + $this->assertFalse(Carbon::hasFormat('Sun 51st', 'D jS')); + $this->assertFalse(Carbon::hasFormat('Sun 21xx', 'D jS')); + + // Regex failure + $this->assertFalse(Carbon::hasFormat('1975-5-1', 'Y-m-d')); + $this->assertFalse(Carbon::hasFormat('19-05-01', 'Y-m-d')); + $this->assertFalse(Carbon::hasFormat('30/12/2019', 'm/d/Y')); + $this->assertFalse(Carbon::hasFormat('12/30/2019', 'd/m/Y')); + + $this->assertTrue(Carbon::hasFormat('2012-12-04 22:59.32130', 'Y-m-d H:s.vi')); + } + + public static function dataForFormatLetters(): array + { + return [ + 'd' => ['d'], + 'D' => ['D'], + 'j' => ['j'], + 'l' => ['l'], + 'N' => ['N'], + 'S' => ['S'], + 'w' => ['w'], + 'z' => ['z'], + 'W' => ['W'], + 'F' => ['F'], + 'm' => ['m'], + 'M' => ['M'], + 'n' => ['n'], + 't' => ['t'], + 'L' => ['L'], + 'o' => ['o'], + 'Y' => ['Y'], + 'y' => ['y'], + 'a' => ['a'], + 'A' => ['A'], + 'B' => ['B'], + 'g' => ['g'], + 'G' => ['G'], + 'h' => ['h'], + 'H' => ['H'], + 'i' => ['i'], + 's' => ['s'], + 'u' => ['u'], + 'v' => ['v'], + 'e' => ['e'], + 'I' => ['I'], + 'O' => ['O'], + 'P' => ['P'], + 'T' => ['T'], + 'Z' => ['Z'], + 'U' => ['U'], + 'c' => ['c'], + 'r' => ['r'], + ]; + } + + #[DataProvider('dataForFormatLetters')] + public function testHasFormatWithSingleLetter($letter) + { + $output = Carbon::now()->format($letter); + $this->assertTrue(Carbon::hasFormat($output, $letter), "'$letter' format should match '$output'"); + } + + public function testIs() + { + $this->assertTrue(Carbon::parse('2019-06-02 12:23:45')->is('2019')); + $this->assertFalse(Carbon::parse('2019-06-02 12:23:45')->is('2018')); + $this->assertTrue(Carbon::parse('2019-06-02 12:23:45')->is('2019-06')); + $this->assertFalse(Carbon::parse('2019-06-02 12:23:45')->is('2018-06')); + $this->assertFalse(Carbon::parse('2019-06-02 12:23:45')->is('2019-07')); + $this->assertTrue(Carbon::parse('2019-06-02 12:23:45')->is('06-02')); + $this->assertFalse(Carbon::parse('2019-06-02 12:23:45')->is('06-03')); + $this->assertFalse(Carbon::parse('2019-06-02 12:23:45')->is('05-02')); + $this->assertTrue(Carbon::parse('2019-06-02 12:23:45')->is('2019-06-02')); + $this->assertFalse(Carbon::parse('2019-06-02 12:23:45')->is('2019-06-03')); + $this->assertFalse(Carbon::parse('2019-06-02 12:23:45')->is('2019-05-02')); + $this->assertFalse(Carbon::parse('2019-06-02 12:23:45')->is('2020-06-02')); + $this->assertTrue(Carbon::parse('2019-06-02 12:23:45')->is('Sunday')); + $this->assertFalse(Carbon::parse('2019-06-02 12:23:45')->is('Monday')); + $this->assertTrue(Carbon::parse('2019-06-02 12:23:45')->is('June')); + $this->assertFalse(Carbon::parse('2019-06-02 12:23:45')->is('May')); + $this->assertFalse(Carbon::parse('2023-10-01 00:00:00')->is('February')); + $this->assertFalse(Carbon::parse('2023-10-01 00:00:00')->is('January')); + $this->assertTrue(Carbon::parse('2019-06-02 12:23:45')->is('12:23')); + $this->assertFalse(Carbon::parse('2019-06-02 12:23:45')->is('12:26')); + $this->assertFalse(Carbon::parse('2019-06-02 12:23:45')->is('12:23:00')); + $this->assertTrue(Carbon::parse('2019-06-02 12:23:45')->is('12h')); + $this->assertFalse(Carbon::parse('2019-06-02 12:23:45')->is('15h')); + $this->assertFalse(Carbon::parse('2019-06-02 12:23:45')->is('12:00')); + $this->assertFalse(Carbon::parse('2019-06-02 12:23:45')->is('15:00')); + $this->assertTrue(Carbon::parse('2019-06-02 15:23:45')->is('3pm')); + $this->assertFalse(Carbon::parse('2019-06-02 15:23:45')->is('4pm')); + $this->assertFalse(Carbon::parse('2019-06-02 15:23:45')->is('3am')); + $this->assertTrue(Carbon::parse('2019-06-02 12:23:45')->is('2019-06-02 12:23')); + $this->assertFalse(Carbon::parse('2019-06-02 12:23:45')->is('2019-06-03 12:23')); + $this->assertFalse(Carbon::parse('2019-06-02 12:23:45')->is('2019-06-02 15:23')); + $this->assertFalse(Carbon::parse('2019-06-02 12:23:45')->is('2019-06-02 12:33')); + $this->assertTrue(Carbon::parse('2019-06-02 12:23:45')->is('2 June 2019')); + $this->assertFalse(Carbon::parse('2019-06-02 12:23:45')->is('1 June 2019')); + $this->assertTrue(Carbon::parse('2019-06-02 12:23:45')->is('June 2019')); + $this->assertFalse(Carbon::parse('2019-06-02 12:23:45')->is('August 2019')); + $this->assertFalse(Carbon::parse('2019-06-02 12:23:45')->is('June 2018')); + } + + public function testHasFormatWithDots() + { + $this->assertTrue(Carbon::hasFormat('2020.09.09', 'Y.m.d')); + $this->assertFalse(Carbon::hasFormat('2020009009', 'Y.m.d')); + $this->assertFalse(Carbon::hasFormat('2020-09-09', 'Y.m.d')); + $this->assertFalse(Carbon::hasFormat('2020*09*09', 'Y.m.d')); + $this->assertFalse(Carbon::hasFormat('2020k09d09', 'Y.m.d')); + } +} diff --git a/tests/CarbonImmutable/MacroTest.php b/tests/CarbonImmutable/MacroTest.php new file mode 100644 index 0000000..5aea75e --- /dev/null +++ b/tests/CarbonImmutable/MacroTest.php @@ -0,0 +1,268 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Tests\CarbonImmutable; + +use BadMethodCallException; +use Carbon\CarbonImmutable as Carbon; +use CarbonTimezoneTrait; +use Closure; +use PHPUnit\Framework\Attributes\RequiresPhpExtension; +use SubCarbonImmutable; +use Tests\AbstractTestCaseWithOldNow; +use Tests\Carbon\Fixtures\FooBar; +use Tests\CarbonImmutable\Fixtures\Mixin; + +class MacroTest extends AbstractTestCaseWithOldNow +{ + #[RequiresPhpExtension('calendar')] + public function testCarbonIsMacroableWhenNotCalledDynamically() + { + Carbon::macro('easterDays', function ($year = 2019) { + return easter_days($year); + }); + + /** @var mixed $now */ + $now = Carbon::now(); + + $this->assertSame(22, $now->easterDays(2020)); + $this->assertSame(31, $now->easterDays()); + + Carbon::macro('otherParameterName', function ($other = true) { + return $other; + }); + + $this->assertTrue($now->otherParameterName()); + } + + #[RequiresPhpExtension('calendar')] + public function testCarbonIsMacroableWhenNotCalledDynamicallyUsingThis() + { + Carbon::macro('diffFromEaster', function ($year) { + /** @var Carbon $date */ + $date = $this; + + return $date->toDateTime()->diff( + Carbon::create($year, 3, 21) + ->setTimezone($date->getTimezone()) + ->addDays(easter_days($year)) + ->endOfDay(), + ); + }); + + /** @var mixed $now */ + $now = Carbon::now(); + + $this->assertSame(1020, $now->diffFromEaster(2020)->days); + } + + #[RequiresPhpExtension('calendar')] + public function testCarbonIsMacroableWhenCalledStatically() + { + Carbon::macro('easterDate', function ($year) { + return Carbon::create($year, 3, 21)->addDays(easter_days($year)); + }); + + $this->assertSame('05/04', Carbon::easterDate(2015)->format('d/m')); + } + + public function testCarbonIsMacroableWithNonClosureCallables() + { + Carbon::macro('lower2', 'strtolower'); + + /** @var mixed $now */ + $now = Carbon::now(); + + $this->assertSame('abc', $now->lower2('ABC')); + $this->assertSame('abc', Carbon::lower2('ABC')); + } + + public function testCarbonIsMixinable() + { + include_once __DIR__.'/Fixtures/Mixin.php'; + $mixin = new Mixin(); + Carbon::mixin($mixin); + Carbon::setUserTimezone('America/Belize'); + + /** @var mixed $date */ + $date = Carbon::parse('2000-01-01 12:00:00', 'UTC'); + + $this->assertSame('06:00 America/Belize', $date->userFormat('H:i e')); + } + + public function testCarbonRaisesExceptionWhenStaticMacroIsNotFound() + { + $this->expectExceptionObject(new BadMethodCallException( + 'Method Carbon\CarbonImmutable::nonExistingStaticMacro does not exist.', + )); + + Carbon::nonExistingStaticMacro(); + } + + public function testCarbonRaisesExceptionWhenMacroIsNotFound() + { + $this->expectExceptionObject(new BadMethodCallException( + 'Method nonExistingMacro does not exist.', + )); + + /** @var mixed $date */ + $date = Carbon::now(); + $date->nonExistingMacro(); + } + + public function testTraitMixin() + { + Carbon::mixin(FooBar::class); + Carbon::setTestNow('2019-07-19 00:00:00'); + + $this->assertSame('supergirl / Friday / immutable', Carbon::super('girl')); + $this->assertSame('superboy / Thursday / immutable', Carbon::parse('2019-07-18')->super('boy')); + + $this->assertInstanceOf(Carbon::class, Carbon::me()); + } + + public function testTraitWithNamedParameters() + { + require_once __DIR__.'/../Fixtures/CarbonTimezoneTrait.php'; + + Carbon::mixin(CarbonTimezoneTrait::class); + $now = Carbon::now(); + $now = eval("return \$now->toAppTz(tz: 'Europe/Paris');"); + + $this->assertSame('Europe/Paris', $now->format('e')); + } + + public function testSerializationAfterTraitChaining() + { + require_once __DIR__.'/../Fixtures/CarbonTimezoneTrait.php'; + + Carbon::mixin(CarbonTimezoneTrait::class); + Carbon::setTestNow('2023-05-24 14:49'); + + $date = Carbon::toAppTz(false, 'Europe/Paris'); + + $this->assertSame('2023-05-24 16:49 Europe/Paris', unserialize(serialize($date))->format('Y-m-d H:i e')); + + $date = Carbon::parse('2023-06-12 11:49')->toAppTz(false, 'Europe/Paris'); + + $this->assertSame('2023-06-12 13:49 Europe/Paris', unserialize(serialize($date))->format('Y-m-d H:i e')); + } + + public function testSubClassMacro() + { + require_once __DIR__.'/../Fixtures/SubCarbonImmutable.php'; + + $subCarbon = new SubCarbonImmutable('2024-01-24 00:00'); + + SubCarbonImmutable::macro('diffInDecades', function (SubCarbonImmutable|string|null $dt = null, $abs = true) { + return (int) ($this->diffInYears($dt, $abs) / 10); + }); + + $this->assertSame(2, $subCarbon->diffInDecades(new SubCarbonImmutable('2049-01-24 00:00'))); + $this->assertSame(2, $subCarbon->diffInDecades('2049-01-24 00:00')); + + SubCarbonImmutable::resetMacros(); + } + + public function testLazyMixinMethodCall() + { + $test = new class() { + public static array $calledMethods = []; + + public function __construct() + { + self::$calledMethods[] = __METHOD__; + } + + public function __destruct() + { + self::$calledMethods[] = __METHOD__; + } + + public static function noReturnType() + { + self::$calledMethods[] = __METHOD__; + + return static fn () => 'foo'; + } + + public static function returnVoid(): void + { + self::$calledMethods[] = __METHOD__; + } + + public static function returnArray(): array + { + self::$calledMethods[] = __METHOD__; + + return []; + } + + public static function returnObject(): object + { + self::$calledMethods[] = __METHOD__; + + return (object) []; + } + + public static function returnClosure(): Closure + { + self::$calledMethods[] = __METHOD__; + + return static fn () => 'foo'; + } + + public static function returnMixed(): mixed + { + self::$calledMethods[] = __METHOD__; + + return static fn () => 'foo'; + } + + public static function returnOtherBuiltIn(): bool + { + self::$calledMethods[] = __METHOD__; + + return true; + } + + public static function returnUnion(): bool|array + { + self::$calledMethods[] = __METHOD__; + + return true; + } + + public static function getCalledMethods(): array + { + return self::$calledMethods; + } + }; + + Carbon::mixin($test); + Carbon::resetMacros(); + + $this->assertSame([ + '__construct', // Only happening because of $test = new class()... but none from Carbon::mixin() + 'noReturnType', + 'returnArray', + 'returnObject', + 'returnClosure', + 'returnMixed', + 'returnUnion', + ], array_map( + static fn (string $name) => explode('::', $name, 2)[1], + $test::getCalledMethods(), + )); + } +} diff --git a/tests/CarbonImmutable/ModifyTest.php b/tests/CarbonImmutable/ModifyTest.php new file mode 100644 index 0000000..e5211b6 --- /dev/null +++ b/tests/CarbonImmutable/ModifyTest.php @@ -0,0 +1,254 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Tests\CarbonImmutable; + +use Carbon\CarbonImmutable as Carbon; +use InvalidArgumentException; +use Tests\AbstractTestCase; + +class ModifyTest extends AbstractTestCase +{ + public function testSimpleModify() + { + $a = new Carbon('2014-03-30 00:00:00'); + $b = $a->addHours(24); + $this->assertSame(24.0, $a->diffInHours($b)); + } + + public function testSimpleModifyWithNamedParameter() + { + $a = new Carbon('2014-03-30 00:00:00'); + $b = $a->addHours(value: 24); + $this->assertSame(24.0, $a->diffInHours($b)); + } + + public function testTimezoneModify() + { + $php81Fix = 1.0; + // For daylight saving time reason 2014-03-30 0h59 is immediately followed by 2h00 + + $a = new Carbon('2014-03-30 00:00:00', 'Europe/London'); + $b = $a->addHours(24); + $this->assertSame(23.0 + $php81Fix, $a->diffInHours($b)); + $this->assertSame(23.0 + $php81Fix, $b->diffInHours($a, true)); + $this->assertSame(-23.0 - $php81Fix, $b->diffInHours($a)); + $this->assertSame(-(23.0 + $php81Fix) * 60, $b->diffInMinutes($a)); + $this->assertSame(-(23.0 + $php81Fix) * 60 * 60, $b->diffInSeconds($a)); + $this->assertSame(-(23.0 + $php81Fix) * 60 * 60 * 1000, $b->diffInMilliseconds($a)); + $this->assertSame(-(23.0 + $php81Fix) * 60 * 60 * 1000000, $b->diffInMicroseconds($a)); + + $a = new Carbon('2014-03-30 00:00:00', 'Europe/London'); + $b = $a->addRealHours(24); + $this->assertSame(-24.0, $b->diffInHours($a, false)); + $this->assertSame(-24.0 * 60, $b->diffInMinutes($a, false)); + $this->assertSame(-24.0 * 60 * 60, $b->diffInSeconds($a, false)); + $this->assertSame(-24.0 * 60 * 60 * 1000, $b->diffInMilliseconds($a, false)); + $this->assertSame(-24.0 * 60 * 60 * 1000000, $b->diffInMicroseconds($a, false)); + $b = $b->subRealHours(24); + $this->assertSame(0.0, $b->diffInHours($a, false)); + $this->assertSame(0.0, $b->diffInHours($a, false)); + + $a = new Carbon('2014-03-30 00:59:00', 'Europe/London'); + $a = $a->addRealHour(); + $this->assertSame('02:59', $a->format('H:i')); + $a = $a->subRealHour(); + $this->assertSame('00:59', $a->format('H:i')); + + $a = new Carbon('2014-03-30 00:59:00', 'Europe/London'); + $a = $a->addRealMinutes(2); + $this->assertSame('02:01', $a->format('H:i')); + $a = $a->subRealMinutes(2); + $this->assertSame('00:59', $a->format('H:i')); + + $a = new Carbon('2014-03-30 00:59:30', 'Europe/London'); + $a = $a->addRealMinute(); + $this->assertSame('02:00:30', $a->format('H:i:s')); + $a = $a->subRealMinute(); + $this->assertSame('00:59:30', $a->format('H:i:s')); + + $a = new Carbon('2014-03-30 00:59:30', 'Europe/London'); + $a = $a->addRealSeconds(40); + $this->assertSame('02:00:10', $a->format('H:i:s')); + $a = $a->subRealSeconds(40); + $this->assertSame('00:59:30', $a->format('H:i:s')); + + $a = new Carbon('2014-03-30 00:59:59', 'Europe/London'); + $a = $a->addRealSecond(); + $this->assertSame('02:00:00', $a->format('H:i:s')); + $a = $a->subRealSecond(); + $this->assertSame('00:59:59', $a->format('H:i:s')); + + $a = new Carbon('2014-03-30 00:59:59.990000', 'Europe/London'); + $a = $a->addRealMilliseconds(20); + $this->assertSame('02:00:00.010000', $a->format('H:i:s.u')); + $a = $a->subRealMilliseconds(20); + $this->assertSame('00:59:59.990000', $a->format('H:i:s.u')); + + $a = new Carbon('2014-03-30 00:59:59.999990', 'Europe/London'); + $a = $a->addRealMicroseconds(20); + $this->assertSame('02:00:00.000010', $a->format('H:i:s.u')); + $a = $a->subRealMicroseconds(20); + $this->assertSame('00:59:59.999990', $a->format('H:i:s.u')); + + $a = new Carbon('2014-03-30 00:59:59.999999', 'Europe/London'); + $a = $a->addRealMicrosecond(); + $this->assertSame('02:00:00.000000', $a->format('H:i:s.u')); + $a = $a->subRealMicrosecond(); + $this->assertSame('00:59:59.999999', $a->format('H:i:s.u')); + + $a = new Carbon('2014-03-30 00:00:00', 'Europe/London'); + $b = $a->addRealDay(); + $this->assertSame(-24.0, $b->diffInHours($a, false)); + $this->assertSame(-24.0 * 60, $b->diffInMinutes($a, false)); + $this->assertSame(-24.0 * 60 * 60, $b->diffInSeconds($a, false)); + $this->assertSame(-24.0 * 60 * 60 * 1000, $b->diffInMilliseconds($a, false)); + $this->assertSame(-24.0 * 60 * 60 * 1000000, $b->diffInMicroseconds($a, false)); + + $a = new Carbon('2014-03-30 00:00:00', 'Europe/London'); + $b = $a->addRealWeeks(1 / 7); + $this->assertSame(-24.0, $b->diffInHours($a, false)); + $this->assertSame(-24.0 * 60, $b->diffInMinutes($a, false)); + $this->assertSame(-24.0 * 60 * 60, $b->diffInSeconds($a, false)); + $this->assertSame(-24.0 * 60 * 60 * 1000, $b->diffInMilliseconds($a, false)); + $this->assertSame(-24.0 * 60 * 60 * 1000000, $b->diffInMicroseconds($a, false)); + + $a = new Carbon('2014-03-30 00:00:00', 'Europe/London'); + $b = $a->addRealMonths(1 / 30); + $this->assertSame(-24.0, $b->diffInHours($a, false)); + $this->assertSame(-24.0 * 60, $b->diffInMinutes($a, false)); + $this->assertSame(-24.0 * 60 * 60, $b->diffInSeconds($a, false)); + $this->assertSame(-24.0 * 60 * 60 * 1000, $b->diffInMilliseconds($a, false)); + $this->assertSame(-24.0 * 60 * 60 * 1000000, $b->diffInMicroseconds($a, false)); + + $a = new Carbon('2014-03-30 00:00:00', 'Europe/London'); + $b = $a->addRealQuarters(1 / 90); + $this->assertSame(-24.0, $b->diffInHours($a, false)); + $this->assertSame(-24.0 * 60, $b->diffInMinutes($a, false)); + $this->assertSame(-24.0 * 60 * 60, $b->diffInSeconds($a, false)); + $this->assertSame(-24.0 * 60 * 60 * 1000, $b->diffInMilliseconds($a, false)); + $this->assertSame(-24.0 * 60 * 60 * 1000000, $b->diffInMicroseconds($a, false)); + + $a = new Carbon('2014-03-30 00:00:00', 'Europe/London'); + $b = $a->addRealYears(1 / 365); + $this->assertSame(-24.0, $b->diffInHours($a, false)); + $this->assertSame(-24.0 * 60, $b->diffInMinutes($a, false)); + $this->assertSame(-24.0 * 60 * 60, $b->diffInSeconds($a, false)); + $this->assertSame(-24.0 * 60 * 60 * 1000, $b->diffInMilliseconds($a, false)); + $this->assertSame(-24.0 * 60 * 60 * 1000000, $b->diffInMicroseconds($a, false)); + + $a = new Carbon('2014-03-30 00:00:00', 'Europe/London'); + $b = $a->addRealDecades(1 / 3650); + $this->assertSame(-24.0, $b->diffInHours($a, false)); + $this->assertSame(-24.0 * 60, $b->diffInMinutes($a, false)); + $this->assertSame(-24.0 * 60 * 60, $b->diffInSeconds($a, false)); + $this->assertSame(-24.0 * 60 * 60 * 1000, $b->diffInMilliseconds($a, false)); + $this->assertSame(-24.0 * 60 * 60 * 1000000, $b->diffInMicroseconds($a, false)); + + $a = new Carbon('2014-03-30 00:00:00', 'Europe/London'); + $b = $a->addRealCenturies(1 / 36500); + $this->assertSame(-24.0, $b->diffInHours($a, false)); + $this->assertSame(-24.0 * 60, $b->diffInMinutes($a, false)); + $this->assertSame(-24.0 * 60 * 60, $b->diffInSeconds($a, false)); + $this->assertSame(-24.0 * 60 * 60 * 1000, $b->diffInMilliseconds($a, false)); + $this->assertSame(-24.0 * 60 * 60 * 1000000, $b->diffInMicroseconds($a, false)); + + $a = new Carbon('2014-03-30 00:00:00', 'Europe/London'); + $b = $a->addRealMillennia(1 / 365000); + $this->assertSame(-24.0, $b->diffInHours($a, false)); + $this->assertSame(-24.0 * 60, $b->diffInMinutes($a, false)); + $this->assertSame(-24.0 * 60 * 60, $b->diffInSeconds($a, false)); + $this->assertSame(-24.0 * 60 * 60 * 1000, $b->diffInMilliseconds($a, false)); + $this->assertSame(-24.0 * 60 * 60 * 1000000, $b->diffInMicroseconds($a, false)); + } + + public function testNextAndPrevious() + { + Carbon::setTestNow('2019-06-02 13:27:09.816752'); + + $this->assertSame('2019-06-02 14:00:00', Carbon::now()->next('2pm')->format('Y-m-d H:i:s')); + $this->assertSame('2019-06-01 14:00:00', Carbon::now()->previous('2pm')->format('Y-m-d H:i:s')); + $this->assertSame('2019-06-02 14:00:00', Carbon::now()->next('14h')->format('Y-m-d H:i:s')); + $this->assertSame('2019-06-01 14:00:00', Carbon::now()->previous('14h')->format('Y-m-d H:i:s')); + $this->assertSame('2019-06-03 09:00:00', Carbon::now()->next('9am')->format('Y-m-d H:i:s')); + $this->assertSame('2019-06-02 09:00:00', Carbon::now()->previous('9am')->format('Y-m-d H:i:s')); + + $this->assertSame('2019-06-02 14:00:00', Carbon::parse('next 2pm')->format('Y-m-d H:i:s')); + $this->assertSame('2019-06-01 14:00:00', Carbon::parse('previous 2pm')->format('Y-m-d H:i:s')); + $this->assertSame('2019-06-02 14:00:00', Carbon::parse('next 14h')->format('Y-m-d H:i:s')); + $this->assertSame('2019-06-01 14:00:00', Carbon::parse('previous 14h')->format('Y-m-d H:i:s')); + $this->assertSame('2019-06-03 09:00:00', Carbon::parse('next 9am')->format('Y-m-d H:i:s')); + $this->assertSame('2019-06-02 09:00:00', Carbon::parse('previous 9am')->format('Y-m-d H:i:s')); + } + + public function testAnchorDay(): void + { + $this->assertSame( + '2023-03-31 00:00:00', + Carbon::parse('2023-02-28')->addMonths(1, anchorDay: 31)->format('Y-m-d H:i:s'), + ); + $this->assertSame( + '2023-04-30 00:00:00', + Carbon::parse('2023-02-28')->addMonths(2, anchorDay: 31)->format('Y-m-d H:i:s'), + ); + $this->assertSame( + '2023-03-31 00:00:00', + Carbon::parse('2023-02-28')->addMonthsNoOverflow(1, anchorDay: 31)->format('Y-m-d H:i:s'), + ); + $this->assertSame( + '2023-04-30 00:00:00', + Carbon::parse('2023-02-28')->addMonthsNoOverflow(2, anchorDay: 31)->format('Y-m-d H:i:s'), + ); + $this->assertSame( + '2024-02-29 00:00:00', + Carbon::parse('2023-02-28')->addYears(1, anchorDay: 29)->format('Y-m-d H:i:s'), + ); + $this->assertSame( + '2025-02-28 00:00:00', + Carbon::parse('2023-02-28')->addYears(2, anchorDay: 29)->format('Y-m-d H:i:s'), + ); + $this->assertSame( + '2024-02-29 00:00:00', + Carbon::parse('2023-02-28')->addYearsNoOverflow(1, anchorDay: 29)->format('Y-m-d H:i:s'), + ); + $this->assertSame( + '2025-02-28 00:00:00', + Carbon::parse('2023-02-28')->addYearsNoOverflow(2, anchorDay: 29)->format('Y-m-d H:i:s'), + ); + $this->assertSame( + '2024-02-29 00:00:00', + Carbon::parse('2023-02-28')->addYearsWithNoOverflow(1, anchorDay: 29)->format('Y-m-d H:i:s'), + ); + $this->assertSame( + '2025-02-28 00:00:00', + Carbon::parse('2023-02-28')->addYearsWithNoOverflow(2, anchorDay: 29)->format('Y-m-d H:i:s'), + ); + $this->assertSame( + '2024-02-29 00:00:00', + Carbon::parse('2023-02-28')->addYearsWithoutOverflow(1, anchorDay: 29)->format('Y-m-d H:i:s'), + ); + $this->assertSame( + '2025-02-28 00:00:00', + Carbon::parse('2023-02-28')->addYearsWithoutOverflow(2, anchorDay: 29)->format('Y-m-d H:i:s'), + ); + } + + public function testAnchorDayIsIncompatibleWithOverflow(): void + { + $this->expectExceptionObject(new InvalidArgumentException( + '$anchorDay is not compatible with overflow', + )); + + Carbon::parse('2023-02-28')->addYearsWithOverflow(2, anchorDay: 29); + } +} diff --git a/tests/CarbonImmutable/SettersTest.php b/tests/CarbonImmutable/SettersTest.php new file mode 100644 index 0000000..5468c0a --- /dev/null +++ b/tests/CarbonImmutable/SettersTest.php @@ -0,0 +1,435 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Tests\CarbonImmutable; + +use Carbon\CarbonImmutable as Carbon; +use Carbon\Exceptions\ImmutableException; +use Carbon\Exceptions\UnitException; +use Carbon\Month; +use DateTimeZone; +use InvalidArgumentException; +use PHPUnit\Framework\Attributes\TestWith; +use RuntimeException; +use Tests\AbstractTestCase; + +class SettersTest extends AbstractTestCase +{ + public function testYearSetter() + { + $this->expectExceptionObject(new ImmutableException( + 'Carbon\CarbonImmutable class is immutable.', + )); + + $d = Carbon::now(); + $d->year = 1995; + } + + public function testMonthSetter() + { + $this->expectExceptionObject(new RuntimeException( + 'Carbon\CarbonImmutable class is immutable.', + )); + + $d = Carbon::now(); + $d->month = 3; + } + + public function testMonthEnumOnWrongUnit() + { + $this->expectExceptionObject(new UnitException( + 'Month enum cannot be used to set hour', + )); + + $d = Carbon::now(); + $d->setHours(Month::February); + } + + public function testMonthEnum() + { + $d = Carbon::parse('2023-10-25 21:14:51'); + $result = $d->setMonth(Month::February); + + $this->assertSame('2023-02-25 21:14:51', $result->format('Y-m-d H:i:s')); + + $result = $d->setMonth(Month::July); + + $this->assertSame('2023-07-25 21:14:51', $result->format('Y-m-d H:i:s')); + } + + public function testMonthFloatFailWithDecimalPart() + { + $this->expectExceptionObject(new InvalidArgumentException( + 'month cannot be changed to float value 2.5, integer expected', + )); + + $d = Carbon::parse('2023-10-25 21:14:51'); + $d->setMonth(2.5); + } + + public function testMonthFloatPassWithZeroDecimalPart() + { + $d = Carbon::parse('2023-10-25 21:14:51'); + $result = $d->setMonth(2.0); + + $this->assertSame('2023-02-25 21:14:51', $result->format('Y-m-d H:i:s')); + } + + public function testMonthSetterWithWrap() + { + $this->expectExceptionObject(new RuntimeException( + 'Carbon\CarbonImmutable class is immutable.', + )); + + $d = Carbon::now(); + $d->month = 13; + } + + public function testDaySetter() + { + $this->expectExceptionObject(new RuntimeException( + 'Carbon\CarbonImmutable class is immutable.', + )); + + $d = Carbon::now(); + $d->day = 2; + } + + public function testDaySetterWithWrap() + { + $this->expectExceptionObject(new RuntimeException( + 'Carbon\CarbonImmutable class is immutable.', + )); + + $d = Carbon::createFromDate(2012, 8, 5); + $d->day = 32; + } + + public function testHourSetter() + { + $this->expectExceptionObject(new RuntimeException( + 'Carbon\CarbonImmutable class is immutable.', + )); + + $d = Carbon::now(); + $d->hour = 2; + } + + public function testHourSetterWithWrap() + { + $this->expectExceptionObject(new RuntimeException( + 'Carbon\CarbonImmutable class is immutable.', + )); + + $d = Carbon::now(); + $d->hour = 25; + } + + public function testMinuteSetter() + { + $this->expectExceptionObject(new RuntimeException( + 'Carbon\CarbonImmutable class is immutable.', + )); + + $d = Carbon::now(); + $d->minute = 2; + } + + public function testMinuteSetterWithWrap() + { + $this->expectExceptionObject(new RuntimeException( + 'Carbon\CarbonImmutable class is immutable.', + )); + + $d = Carbon::now(); + $d->minute = 65; + } + + public function testSecondSetter() + { + $this->expectExceptionObject(new RuntimeException( + 'Carbon\CarbonImmutable class is immutable.', + )); + + $d = Carbon::now(); + $d->second = 2; + } + + public function testTimeSetter() + { + $d = Carbon::now(); + $d = $d->setTime(1, 1, 1); + $this->assertSame(1, $d->second); + $d = $d->setTime(1, 1); + $this->assertSame(0, $d->second); + } + + public function testTimeSetterWithChaining() + { + $d = Carbon::now(); + $d = $d->setTime(2, 2, 2)->setTime(1, 1, 1); + $this->assertInstanceOfCarbon($d); + $this->assertSame(1, $d->second); + $d = $d->setTime(2, 2, 2)->setTime(1, 1); + $this->assertInstanceOfCarbon($d); + $this->assertSame(0, $d->second); + } + + public function testTimeSetterWithZero() + { + $d = Carbon::now(); + $d = $d->setTime(1, 1); + $this->assertSame(0, $d->second); + } + + public function testDateTimeSetter() + { + $d = Carbon::now(); + $d = $d->setDateTime($d->year, $d->month, $d->day, 1, 1, 1); + $this->assertSame(1, $d->second); + } + + public function testDateTimeSetterWithZero() + { + $d = Carbon::now(); + $d = $d->setDateTime($d->year, $d->month, $d->day, 1, 1); + $this->assertSame(0, $d->second); + } + + public function testDateTimeSetterWithChaining() + { + $d = Carbon::now(); + $d = $d->setDateTime(2013, 9, 24, 17, 4, 29); + $this->assertInstanceOfCarbon($d); + $d = $d->setDateTime(2014, 10, 25, 18, 5, 30); + $this->assertInstanceOfCarbon($d); + $this->assertCarbon($d, 2014, 10, 25, 18, 5, 30); + } + + /** + * @link https://github.com/briannesbitt/Carbon/issues/539 + */ + public function testSetDateAfterStringCreation() + { + $d = new Carbon('first day of this month'); + $this->assertSame(1, $d->day); + $d = $d->setDate($d->year, $d->month, 12); + $this->assertSame(12, $d->day); + } + + public function testSecondSetterWithWrap() + { + $this->expectExceptionObject(new RuntimeException( + 'Carbon\CarbonImmutable class is immutable.', + )); + + $d = Carbon::now(); + $d->second = 65; + } + + public function testTimestampSetter() + { + $this->expectExceptionObject(new RuntimeException( + 'Carbon\CarbonImmutable class is immutable.', + )); + + $d = Carbon::now(); + $d->timestamp = 10; + } + + public function testSetTimezoneWithInvalidTimezone() + { + $this->expectExceptionObject(new InvalidArgumentException( + 'Unknown or bad timezone (sdf)', + )); + + $d = Carbon::now(); + $d->setTimezone('sdf'); + } + + public function testTimezoneWithInvalidTimezone() + { + $this->expectExceptionObject(new RuntimeException( + 'Carbon\CarbonImmutable class is immutable.', + )); + + /** @var mixed $d */ + $d = Carbon::now(); + $d->timezone = 'sdf'; + } + + public function testTimezoneWithInvalidTimezoneSetter() + { + $this->expectExceptionObject(new InvalidArgumentException( + 'Unknown or bad timezone (sdf)', + )); + + $d = Carbon::now(); + $d->timezone('sdf'); + } + + public function testTzWithInvalidTimezone() + { + $this->expectExceptionObject(new RuntimeException( + 'Carbon\CarbonImmutable class is immutable.', + )); + + /** @var mixed $d */ + $d = Carbon::now(); + $d->tz = 'sdf'; + } + + public function testTzWithInvalidTimezoneSetter() + { + $this->expectExceptionObject(new InvalidArgumentException( + 'Unknown or bad timezone (sdf)', + )); + + $d = Carbon::now(); + $d->tz('sdf'); + } + + public function testSetTimezoneUsingString() + { + $d = Carbon::now(); + $d = $d->setTimezone('America/Toronto'); + $this->assertSame('America/Toronto', $d->tzName); + } + + public function testShiftTimezone() + { + $d = Carbon::parse('2018-08-13 10:53:12', 'Europe/Paris'); + $d2 = $d->copy()->setTimezone('America/Toronto'); + $this->assertSame(0, $d2->getTimestamp() - $d->getTimestamp()); + $this->assertSame('04:53:12', $d2->format('H:i:s')); + + $d = Carbon::parse('2018-08-13 10:53:12', 'Europe/Paris'); + $d2 = $d->copy()->shiftTimezone('America/Toronto'); + $this->assertSame(21600, $d2->getTimestamp() - $d->getTimestamp()); + $this->assertSame('America/Toronto', $d2->tzName); + $this->assertSame('10:53:12', $d2->format('H:i:s')); + + $d = Carbon::parse('2018-03-25 00:53:12.321654 America/Toronto')->shiftTimezone('Europe/Oslo'); + $this->assertSame('2018-03-25 00:53:12.321654 Europe/Oslo', $d->format('Y-m-d H:i:s.u e')); + } + + public function testTimezoneUsingString() + { + $this->expectExceptionObject(new RuntimeException( + 'Carbon\CarbonImmutable class is immutable.', + )); + + /** @var mixed $d */ + $d = Carbon::now(); + $d->timezone = 'America/Toronto'; + } + + public function testTzUsingString() + { + $this->expectExceptionObject(new RuntimeException( + 'Carbon\CarbonImmutable class is immutable.', + )); + + /** @var mixed $d */ + $d = Carbon::now(); + $d->tz = 'America/Toronto'; + } + + public function testSetTimezoneUsingDateTimeZone() + { + $d = Carbon::now(); + $d = $d->setTimezone(new DateTimeZone('America/Toronto')); + $this->assertSame('America/Toronto', $d->tzName); + } + + public function testTimezoneUsingDateTimeZone() + { + $this->expectExceptionObject(new RuntimeException( + 'Carbon\CarbonImmutable class is immutable.', + )); + + /** @var mixed $d */ + $d = Carbon::now(); + $d->timezone = new DateTimeZone('America/Toronto'); + } + + public function testTzUsingDateTimeZone() + { + $this->expectExceptionObject(new RuntimeException( + 'Carbon\CarbonImmutable class is immutable.', + )); + + /** @var mixed $d */ + $d = Carbon::now(); + $d->tz = new DateTimeZone('America/Toronto'); + } + + public function testInvalidSetter() + { + $this->expectExceptionObject(new RuntimeException( + 'Carbon\CarbonImmutable class is immutable.', + )); + + /** @var mixed $d */ + $d = Carbon::now(); + $d->doesNotExit = 'bb'; + } + + #[TestWith([9, 15, 30, '09:15:30'])] + #[TestWith([9, 15, 0, '09:15'])] + #[TestWith([9, 0, 0, '09'])] + #[TestWith([9, 5, 3, '9:5:3'])] + #[TestWith([9, 5, 0, '9:5'])] + #[TestWith([9, 0, 0, '9'])] + public function testSetTimeFromTimeString(int $hour, int $minute, int $second, string $time) + { + Carbon::setTestNow(Carbon::create(2016, 2, 12, 1, 2, 3)); + $d = Carbon::now()->setTimeFromTimeString($time); + $this->assertCarbon($d, 2016, 2, 12, $hour, $minute, $second); + } + + public function testWeekendDaysSetter() + { + $weekendDays = [Carbon::FRIDAY, Carbon::SATURDAY]; + $d = Carbon::now(); + $d->setWeekendDays($weekendDays); + $this->assertSame($weekendDays, $d->getWeekendDays()); + Carbon::setWeekendDays([Carbon::SATURDAY, Carbon::SUNDAY]); + } + + public function testMidDayAtSetter() + { + $d = Carbon::now(); + $d->setMidDayAt(11); + $this->assertSame(11, $d->getMidDayAt()); + $d->setMidDayAt(12); + $this->assertSame(12, $d->getMidDayAt()); + } + + public function testSetter() + { + $d = Carbon::now(); + $d->setMidDayAt(11); + $this->assertSame(11, $d->getMidDayAt()); + $d->setMidDayAt(12); + $this->assertSame(12, $d->getMidDayAt()); + } + + public function testSetUnitNoOverflowFebruary() + { + $d = Carbon::parse('2024-02-29')->setUnitNoOverFlow('day', 31, 'month'); + + $this->assertInstanceOf(Carbon::class, $d); + $this->assertSame('2024-02-29 23:59:59.999999', $d->format('Y-m-d H:i:s.u')); + } +} diff --git a/tests/CarbonPeriod/GettersTest.php b/tests/CarbonPeriod/GettersTest.php new file mode 100644 index 0000000..b868080 --- /dev/null +++ b/tests/CarbonPeriod/GettersTest.php @@ -0,0 +1,480 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Tests\CarbonPeriod; + +use Carbon\Carbon; +use Carbon\CarbonImmutable; +use Carbon\CarbonInterval; +use Carbon\CarbonPeriod; +use Carbon\Exceptions\UnknownGetterException; +use Carbon\Exceptions\UnreachableException; +use DateTime; +use Tests\AbstractTestCase; +use Tests\CarbonPeriod\Fixtures\CarbonPeriodFactory; + +class GettersTest extends AbstractTestCase +{ + public function testGetStartDate() + { + $period = CarbonPeriodFactory::withStartIntervalEnd(static::$periodClass); + + $date = $period->getStartDate(); + + $this->assertInstanceOfCarbon($date); + + $this->assertSame('2012-07-01 17:30:00', $date->format('Y-m-d H:i:s')); + } + + public function testGetEndDate() + { + $period = CarbonPeriodFactory::withStartIntervalEnd(static::$periodClass); + + $date = $period->getEndDate(); + + $this->assertInstanceOfCarbon($date); + + $this->assertSame('2012-07-15 11:15:00', $date->format('Y-m-d H:i:s')); + } + + public function testGetDateInterval() + { + $period = CarbonPeriodFactory::withStartIntervalEnd(static::$periodClass); + + $interval = $period->getDateInterval(); + + $this->assertInstanceOfCarbonInterval($interval); + + $this->assertSame('P3DT5H', $interval->spec()); + } + + public function testGetRecurrences() + { + $periodClass = static::$periodClass; + + $recurrences = $periodClass::create(new DateTime(), 5)->getRecurrences(); + + $this->assertSame(5, $recurrences); + + $period = $periodClass::create('2024-09-01/3 days/2024-09-30'); + + $this->assertNull($period->get('recurrences')); + + $period = $periodClass::create('R3/2024-09-01/3 days'); + + $this->assertSame(3, $period->get('recurrences')); + } + + public function testGetDefaultDateInterval() + { + $periodClass = static::$periodClass; + + $period = $periodClass::create(Carbon::parse('2015-09-30'), Carbon::parse('2015-10-03')); + + $this->assertInstanceOfCarbonInterval($period->getDateInterval()); + + $this->assertSame('P1D', $period->getDateInterval()->spec()); + } + + public function testModifyStartDate() + { + $period = CarbonPeriodFactory::withStartIntervalEnd(static::$periodClass); + + $period->getStartDate()->subDays(3); + + $this->assertSame('2012-07-01', $period->getStartDate()->format('Y-m-d')); + } + + public function testModifyEndDate() + { + $period = CarbonPeriodFactory::withStartIntervalEnd(static::$periodClass); + + $period->getEndDate()->addDays(3); + + $this->assertSame('2012-07-15', $period->getEndDate()->format('Y-m-d')); + } + + public function testModifyDateInterval() + { + $period = CarbonPeriodFactory::withStartIntervalEnd(static::$periodClass); + + $period->getDateInterval()->days(5)->hours(0); + + $this->assertSame('P3DT5H', $period->getDateInterval()->spec()); + } + + public function testGetOptions() + { + $periodClass = static::$periodClass; + + $period = new $periodClass(); + + $this->assertPeriodOptions(0, $period); + + $this->assertTrue($period->isStartIncluded()); + $this->assertTrue($period->isEndIncluded()); + + if (PHP_VERSION < 8.2) { + $this->assertTrue($period->include_start_date); + $this->assertTrue($period->include_end_date); + } + + $period = new $periodClass(new DateTime(), new DateTime(), $options = $periodClass::EXCLUDE_START_DATE | $periodClass::EXCLUDE_END_DATE); + + $this->assertPeriodOptions($options, $period); + + $this->assertFalse($period->isStartIncluded()); + $this->assertFalse($period->isEndIncluded()); + + if (PHP_VERSION < 8.2) { + $this->assertFalse($period->include_start_date); + $this->assertFalse($period->include_end_date); + } + } + + public function testOverlaps() + { + $periodClass = static::$periodClass; + + $range1 = $periodClass::create('2019-01-26', '2019-03-03'); + $range2 = $periodClass::create('2019-02-15', '2019-04-01'); + + $this->assertTrue($range1->overlaps($range2)); + $this->assertTrue($range2->overlaps($range1)); + + $range1 = $periodClass::create('2019-01-26', '2019-02-13'); + $range2 = $periodClass::create('2019-02-15', '2019-04-01'); + + $this->assertFalse($range1->overlaps($range2)); + $this->assertFalse($range2->overlaps($range1)); + + $range1 = $periodClass::create('2019-01-26', '2019-02-15'); + $range2 = $periodClass::create('2019-02-15', '2019-04-01'); + + $this->assertFalse($range1->overlaps($range2)); + $this->assertFalse($range2->overlaps($range1)); + + $range1 = $periodClass::create('2019-01-26', '2019-02-15 00:00:01'); + $range2 = $periodClass::create('2019-02-15', '2019-04-01'); + + $this->assertTrue($range1->overlaps($range2)); + $this->assertTrue($range2->overlaps($range1)); + + $range1 = $periodClass::create('2019-01-26', '2019-02-15 00:00:01'); + $range2 = $periodClass::create('2019-02-15 00:00:01', '2019-04-01'); + + $this->assertFalse($range1->overlaps($range2)); + $this->assertFalse($range2->overlaps($range1)); + + $range1 = $periodClass::create('2019-01-26 10:30:12', '2019-01-26 13:30:12'); + $range2 = $periodClass::create('2019-01-26 10:30:05', '2019-01-26 13:32:12'); + + $this->assertTrue($range1->overlaps($range2)); + $this->assertTrue($range2->overlaps($range1)); + + $range1 = $periodClass::create('2019-01-26 10:30:12', INF); + $range2 = $periodClass::create('2999-01-26 10:30:05', '2999-01-26 13:32:12'); + + $this->assertFalse($range1->calculateEnd()->isStartOfTime()); + $this->assertTrue($range1->calculateEnd()->isEndOfTime()); + $this->assertFalse($range2->calculateEnd()->isStartOfTime()); + $this->assertFalse($range2->calculateEnd()->isEndOfTime()); + $this->assertTrue($range1->overlaps($range2)); + $this->assertTrue($range2->overlaps($range1)); + + $range1 = $periodClass::create('2019-01-26 10:30:12', CarbonInterval::day(-1), INF); + $range2 = $periodClass::create('2999-01-26 10:30:05', '2999-01-26 13:32:12'); + + $this->assertTrue($range1->calculateEnd()->isStartOfTime()); + $this->assertFalse($range1->calculateEnd()->isEndOfTime()); + $this->assertFalse($range2->calculateEnd()->isStartOfTime()); + $this->assertFalse($range2->calculateEnd()->isEndOfTime()); + $this->assertFalse($range1->overlaps($range2)); + $this->assertFalse($range2->overlaps($range1)); + + $range1 = $periodClass::create('2019-01-26 10:30:12', INF); + $range2 = $periodClass::create('1975-01-26 10:30:05', '1975-01-26 13:32:12'); + + $this->assertFalse($range1->overlaps($range2)); + $this->assertFalse($range2->overlaps($range1)); + + $range1 = $periodClass::create('2019-01-26 10:30:12', CarbonInterval::day(-1), INF); + $range2 = $periodClass::create('1975-01-26 10:30:05', '1975-01-26 13:32:12'); + + $this->assertTrue($range1->overlaps($range2)); + $this->assertTrue($range2->overlaps($range1)); + + $range1 = $periodClass::create('2019-01-26 10:30:12', INF); + $range2 = $periodClass::create('2999-01-26 10:30:05', INF); + + $this->assertTrue($range1->overlaps($range2)); + $this->assertTrue($range2->overlaps($range1)); + + $range1 = $periodClass::create('2019-01-26 10:30:12', CarbonInterval::day(-1), INF); + $range2 = $periodClass::create('2999-01-26 10:30:05', INF); + + $this->assertFalse($range1->overlaps($range2)); + $this->assertFalse($range2->overlaps($range1)); + + $range1 = $periodClass::create('2019-01-26 10:30:12', INF); + $range2 = $periodClass::create('1975-01-26 10:30:05', INF); + + $this->assertTrue($range1->overlaps($range2)); + $this->assertTrue($range2->overlaps($range1)); + + $range1 = $periodClass::create('2019-01-26 10:30:12', INF); + $range2 = $periodClass::create('1975-01-26 10:30:05', CarbonInterval::day(-1), INF); + + $this->assertFalse($range1->overlaps($range2)); + $this->assertFalse($range2->overlaps($range1)); + + $range1 = $periodClass::create('2019-01-26 10:30:12', CarbonInterval::day(-1), INF); + $range2 = $periodClass::create('1975-01-26 10:30:05', INF); + + $this->assertTrue($range1->overlaps($range2)); + $this->assertTrue($range2->overlaps($range1)); + + $range1 = $periodClass::create('2019-01-26 10:30:12', CarbonInterval::day(), 365, $periodClass::EXCLUDE_START_DATE); + $range2 = $periodClass::create('2020-01-26 10:30:05', '2020-01-27 10:30:05'); + + $this->assertTrue($range1->overlaps($range2)); + $this->assertTrue($range2->overlaps($range1)); + + $range1 = $periodClass::create('2019-01-26 10:30:12', CarbonInterval::day(), 365, $periodClass::EXCLUDE_START_DATE); + $range2 = $periodClass::create('2020-01-26 10:30:20', '2020-01-27 10:30:20'); + + $this->assertFalse($range1->overlaps($range2)); + $this->assertFalse($range2->overlaps($range1)); + + $range1 = $periodClass::create('2019-01-26 10:30:12', CarbonInterval::day(), 365); + $range2 = $periodClass::create('2020-01-27 10:30:20', '2020-01-28 10:30:20'); + + $this->assertFalse($range1->overlaps($range2)); + $this->assertFalse($range2->overlaps($range1)); + + $range1 = $periodClass::create('2019-01-26 10:30:12', CarbonInterval::day(), INF); + (function () { + $this->dateInterval->subDays(1); + })->call($range1); + $range2 = $periodClass::create('2999-01-26 10:30:05', '2999-01-26 13:32:12'); + + $this->assertFalse($range1->overlaps($range2)); + $this->assertFalse($range2->overlaps($range1)); + + $range1 = $periodClass::create('2019-01-26 10:30:12', CarbonInterval::day(), INF); + (function () { + $this->dateInterval->subDays(1); + })->call($range1); + $range2 = $periodClass::create('2018-01-26 10:30:05', '2019-01-26 13:32:12'); + + $this->assertTrue($range1->overlaps($range2)); + $this->assertTrue($range2->overlaps($range1)); + } + + public function testOverlapsErrorForNullEnd() + { + $periodClass = static::$periodClass; + + $this->expectExceptionObject(new UnreachableException( + "Could not calculate period end without either explicit end or recurrences.\n". + "If you're looking for a forever-period, use ->setRecurrences(INF).", + )); + + $periodClass::create('2019-01-26 10:30:12', null)->overlaps('R2/2019-01-31T10:30:45Z/P2D'); + } + + public function testOverlapsErrorForMaxAttempts() + { + $periodClass = static::$periodClass; + + $this->expectExceptionObject(new UnreachableException( + 'Could not calculate period end after iterating 10000 times.', + )); + + $period = $periodClass::create('2019-01-26 10:30:12', CarbonInterval::minute(), 98282828); + $period = $period->addFilter(function ($date) { + return $date->minute % 2; + }); + $period->overlaps('R2/2019-01-31T10:30:45Z/P2D'); + } + + public function testOverlapsCalculated() + { + $periodClass = static::$periodClass; + + $this->assertTrue($periodClass::create('2019-01-27', '2019-02-02')->overlaps('R2/2019-01-31T10:30:45Z/P2D')); + $this->assertTrue($periodClass::create('2019-01-27', '2019-02-02')->overlaps('2018-12-31/2019-02-01')); + $this->assertFalse($periodClass::create('2019-01-27', '2019-02-02')->overlaps('R6/2018-12-31/P3D')); + $this->assertTrue($periodClass::create('2019-01-27', '2019-02-02')->overlaps('R6/2018-12-31/P6D')); + $this->assertFalse($periodClass::create('R6/2018-12-31/P1D')->overlaps('R3/2019-01-05/PT3H')); + $this->assertTrue($periodClass::create('R7/2018-12-31/P1D')->overlaps('R3/2019-01-05/PT3H')); + } + + public function testOverlapsWithDatesCouple() + { + $periodClass = static::$periodClass; + $carbonClass = $periodClass === CarbonPeriod::class ? Carbon::class : CarbonImmutable::class; + + $this->assertTrue($carbonClass::parse('2019-01-26')->toPeriod('2019-03-03')->overlaps('2019-02-15', '2019-04-01')); + $this->assertTrue($carbonClass::parse('2019-02-15')->toPeriod('2019-04-01')->overlaps('2019-02-15', '2019-04-01')); + $this->assertTrue($periodClass::create('2019-01-26', '2019-03-03')->overlaps('2019-02-15', '2019-04-01')); + $this->assertTrue($periodClass::create('2019-01-26', '2019-03-03')->overlaps($carbonClass::parse('2019-02-15')->toPeriod('2019-04-01'))); + $this->assertTrue($carbonClass::parse('2019-01-26')->toPeriod('2019-03-03')->overlaps($carbonClass::parse('2019-02-15'), '2019-04-01')); + $this->assertTrue(Carbon::parse('2019-02-15')->toPeriod('2019-04-01')->overlaps('2019-02-15', CarbonImmutable::parse('2019-04-01'))); + $this->assertTrue(CarbonImmutable::parse('2019-02-15')->toPeriod('2019-04-01')->overlaps('2019-02-15', Carbon::parse('2019-04-01'))); + $this->assertTrue($periodClass::create('2019-01-26', '2019-03-03')->overlaps(new DateTime('2019-02-15'), new DateTime('2019-04-01'))); + + $this->assertFalse($carbonClass::parse('2018-01-26')->toPeriod('2018-03-03')->overlaps('2019-02-15', '2019-04-01')); + $this->assertFalse($carbonClass::parse('2018-02-15')->toPeriod('2018-04-01')->overlaps('2019-02-15', '2019-04-01')); + $this->assertFalse($periodClass::create('2018-01-26', '2018-02-13')->overlaps('2019-02-15', '2019-04-01')); + $this->assertFalse($periodClass::create('2018-01-26', '2018-02-13')->overlaps($carbonClass::parse('2019-02-15')->toPeriod('2019-04-01'))); + $this->assertFalse($carbonClass::parse('2018-01-26')->toPeriod('2018-03-03')->overlaps($carbonClass::parse('2019-02-15'), '2019-04-01')); + $this->assertFalse(Carbon::parse('2018-02-15')->toPeriod('2018-04-01')->overlaps('2019-02-15', CarbonImmutable::parse('2019-04-01'))); + $this->assertFalse($periodClass::create('2018-01-26', '2018-02-13')->overlaps(new DateTime('2019-02-15'), new DateTime('2019-04-01'))); + } + + public function testIsStarted() + { + $periodClass = static::$periodClass; + + Carbon::setTestNow('2019-08-03 11:47:00'); + + $this->assertFalse($periodClass::create('2019-08-03 11:47:01', '2019-08-03 12:00:00')->isStarted()); + $this->assertFalse($periodClass::create('2020-01-01', '2020-07-01')->isStarted()); + $this->assertTrue($periodClass::create('2019-08-03 01:00:00', '2019-08-03 09:00:00')->isStarted()); + $this->assertTrue($periodClass::create('2019-01-01', '2019-07-01')->isStarted()); + $this->assertTrue($periodClass::create('2019-08-01', '2019-08-15')->isStarted()); + $this->assertTrue($periodClass::create('2019-08-03 11:47:00', '2019-08-15 11:47:00')->isStarted()); + } + + public function testIsEnded() + { + $periodClass = static::$periodClass; + + Carbon::setTestNow('2019-08-03 11:47:00'); + + $this->assertFalse($periodClass::create('2019-08-03 11:47:01', '2019-08-03 12:00:00')->isEnded()); + $this->assertFalse($periodClass::create('2020-01-01', '2020-07-01')->isEnded()); + $this->assertFalse($periodClass::create('2019-08-01', '2019-08-15')->isEnded()); + $this->assertFalse($periodClass::create('2019-08-03 11:47:00', '2019-08-15 11:47:00')->isEnded()); + $this->assertTrue($periodClass::create('2019-08-03 01:00:00', '2019-08-03 09:00:00')->isEnded()); + $this->assertTrue($periodClass::create('2019-01-01', '2019-07-01')->isEnded()); + $this->assertTrue($periodClass::create('2019-08-02 11:47:00', '2019-08-03 11:47:00')->isEnded()); + } + + public function testIsInProgress() + { + $periodClass = static::$periodClass; + + Carbon::setTestNow('2019-08-03 11:47:00'); + + $this->assertFalse($periodClass::create('2019-08-03 11:47:01', '2019-08-03 12:00:00')->isInProgress()); + $this->assertFalse($periodClass::create('2020-01-01', '2020-07-01')->isInProgress()); + $this->assertFalse($periodClass::create('2019-08-03 01:00:00', '2019-08-03 09:00:00')->isInProgress()); + $this->assertFalse($periodClass::create('2019-01-01', '2019-07-01')->isInProgress()); + $this->assertFalse($periodClass::create('2019-08-02 11:47:00', '2019-08-03 11:47:00')->isInProgress()); + $this->assertTrue($periodClass::create('2019-08-03 11:47:00', '2019-08-15 11:47:00')->isInProgress()); + $this->assertTrue($periodClass::create('2019-08-01', '2019-08-15')->isInProgress()); + } + + public function testIsset() + { + $periodClass = static::$periodClass; + + $this->assertTrue(isset($periodClass::create('2019-08-01', '2019-08-15')->startDate)); + $this->assertFalse(isset($periodClass::create('2019-08-01', '2019-08-15')->middleDate)); + } + + public function testMagicGet() + { + $periodClass = static::$periodClass; + + $this->assertSame( + '2019-08-01', + $periodClass::create('2019-08-01', '2019-08-15')->startDate->format('Y-m-d'), + ); + $this->assertSame( + 'en', + $periodClass::create('2019-08-01', '2019-08-15')->locale, + ); + $this->assertSame( + 'fi', + $periodClass::create('2019-08-01', '2019-08-15')->locale('fi')->locale, + ); + } + + public function testGet() + { + $periodClass = static::$periodClass; + + $this->assertSame( + '2019-08-01', + $periodClass::create('2019-08-01', '2019-08-15')->get('start')->format('Y-m-d'), + ); + } + + public function testUnknownGetter() + { + $periodClass = static::$periodClass; + $this->expectExceptionObject(new UnknownGetterException('middle')); + + $periodClass::create('2019-08-01', '2019-08-15')->get('middle'); + } + + public function testGetEnd() + { + $periodClass = static::$periodClass; + $period = $periodClass::create('2024-09-01/3 days/2024-09-30'); + + $this->assertSame('2024-09-30 00:00:00', $period->end->format('Y-m-d H:i:s')); + $this->assertSame('2024-09-30 00:00:00', $period->endDate->format('Y-m-d H:i:s')); + } + + public function testEndPropertySyncsAfterSetEndDate() + { + $periodClass = static::$periodClass; + $period = $periodClass::create('2024-09-01/3 days/2024-09-30'); + $period = $period->setEndDate('2025-06-15'); + $this->assertSame('2025-06-15 00:00:00', $period->end->format('Y-m-d H:i:s')); + $this->assertSame('2025-06-15 00:00:00', $period->getEndDate()->format('Y-m-d H:i:s')); + $period2 = $periodClass::between('2024-01-01', '2024-12-31'); + $period2 = $period2->setEndDate('2026-03-01'); + $this->assertSame('2026-03-01 00:00:00', $period2->end->format('Y-m-d H:i:s')); + } + + public function testGetCurrent() + { + $periodClass = static::$periodClass; + $period = $periodClass::create('2024-09-01/3 days/2024-09-30'); + + $this->assertSame('2024-09-01 00:00:00', $period->get('current')->format('Y-m-d H:i:s')); + + $period->next(); + + $this->assertSame('2024-09-04 00:00:00', $period->get('current')->format('Y-m-d H:i:s')); + } + + public function testGetInclude() + { + $periodClass = static::$periodClass; + $period = $periodClass::create('2024-09-01/3 days/2024-09-30'); + + $this->assertTrue($period->includeStartDate); + $this->assertTrue($period->includeEndDate); + + $period = $periodClass::create('2024-09-01/3 days/2024-09-30')->excludeStartDate()->excludeEndDate(); + + $this->assertFalse($period->includeStartDate); + $this->assertFalse($period->includeEndDate); + } +}