Carbon-backed implementation of the phpnomad/chrono catalog. Ships one concrete class, CarbonChronoStrategy, that fulfills every chrono interface Carbon can natively cover.
PHP 8.2 or newer, phpnomad/chrono ^1.0, nesbot/carbon ^2.72 || ^3.0.
composer require phpnomad/carbon-integrationThe package's Initializer registers CarbonChronoStrategy against the chrono catalog. Apps using PHPNomad's loader pick this up automatically.
A single CarbonChronoStrategy instance fulfills these 28 chrono interfaces:
ClockStrategyCanCheckIfPast,CanCheckIfFuture,CanCheckIfWeekend,CanCheckIfWeekdayCanCheckSameDay,CanCheckSameMonth,CanCheckSameYear,CanCheckBetweenCanApplyModifier,CanAddInterval,CanSubtractIntervalCanGetStartOfDay,CanGetEndOfDay,CanGetStartOfMonth,CanGetEndOfMonth,CanGetStartOfYear,CanGetEndOfYearCanGetDifference,CanGetDifferenceInDays,CanGetDifferenceInHours,CanGetDifferenceInMinutes,CanGetDifferenceInSecondsCanParseDate,CanParseDateWithFormatCanFormatDate,CanFormatLocalizedDate,CanFormatRelativeTime
HasTimezone and HasLocale are intentionally not implemented by this integration. Carbon does not own the platform's timezone or locale; those come from the host environment.
The CarbonChronoStrategy constructor declares both as dependencies:
public function __construct(
HasTimezone $timezone,
HasLocale $locale,
)Pair this integration with one that provides those interfaces — for example phpnomad/wordpress-integration, which resolves them from WordPress site settings. Without a HasTimezone and HasLocale binding in the container, the strategy cannot be instantiated.
Model-side chrono interfaces (HasCreatedDate, HasModifiedDate) are likewise not implemented here — they are contracts for domain models, not platform capabilities.
A few decisions worth knowing about:
isBetweenis inclusive on both bounds, matching Carbon'sbetween(true)default.apply()uses nativeDateTimeImmutable::modify(), so month overflow follows PHP's default behavior (Jan 31 + "1 month" is March 3). For month-end-safe arithmetic, preferCanAddIntervalwith an explicitDateIntervalor use Carbon'saddMonthsNoOverflowdirectly.parseFormat()throwsInvalidArgumentExceptionwhen the input cannot be parsed against the supplied format.diffIn*methods are signed.diffInDays($a, $b)returns positive when$bis after$aand negative otherwise. Fractional results from Carbon 3 are truncated to integers.- Carbon's static
setTestNow()is honored bynow()and therefore by every predicate that consults it, which makes the whole strategy deterministic in tests.
Because now() delegates to CarbonImmutable::now(), Carbon's standard test helper works without any chrono-specific machinery:
use Carbon\CarbonImmutable;
CarbonImmutable::setTestNow('2026-05-27 12:00:00');
// ... exercise code that uses CarbonChronoStrategy
CarbonImmutable::setTestNow(); // clearFor PSR-20-style fixed clocks, bind Lcobucci\Clock\FrozenClock (or any PSR-20 implementation) to ClockStrategy in your DI container instead — it will replace just the clock binding while leaving the rest of the Carbon-backed cluster intact.