Skip to content

Repository files navigation

PHPNomad Chrono

Time-related strategy interfaces for PHPNomad. A catalog of narrow capabilities that integration packages implement against any underlying time library — PSR-20, Carbon, Tokei, lcobucci/clock, symfony/clock, WordPress core, native PHP — so consumers can compose time-handling capabilities across libraries without touching call sites.

This package ships interfaces only. Pair it with one or more integration packages — for example phpnomad/wordpress-integration, which binds WordPress's current_datetime(), wp_timezone(), wp_date(), and human_time_diff() to the appropriate interfaces.

Requirements

PHP 8.2 or newer.

Installation

composer require phpnomad/chrono

You will also need at least one concrete ClockStrategy binding. On WordPress, install phpnomad/wordpress-integration and the wiring is automatic. Elsewhere, bind any PSR-20ClockInterface implementation (e.g. lcobucci/clock or symfony/clock) to ClockStrategy in your composition root.

Usage

Inject the capabilities you need. A consumer that does not care about formatting or arithmetic depends on ClockStrategy alone:

useDateTimeImmutable;
usePHPNomad\Chrono\Interfaces\CanCheckIfPast;
usePHPNomad\Chrono\Interfaces\ClockStrategy;
finalclass TokenService
{
publicfunction__construct(
privateClockStrategy$clock,
privateCanCheckIfPast$past,
) {}
publicfunctionisExpired(DateTimeImmutable$expiresAt): bool
{
return$this->past->isPast($expiresAt);
}
publicfunctionissueExpiringIn(string$relative): DateTimeImmutable
{
return$this->clock->now()->modify($relative);
}
}

In tests, bind a frozen ClockStrategy and a stub CanCheckIfPast:

$clock = newLcobucci\Clock\FrozenClock(newDateTimeImmutable('2026-05-27T12:00:00Z'));
$past = newclass ($clock) implements CanCheckIfPast {
publicfunction__construct(privateClockStrategy$clock) {}
publicfunctionisPast(DateTimeImmutable$i): bool { return$i < $this->clock->now(); }
};
$service = newTokenService($clock, $past);
$this->assertFalse($service->isExpired(newDateTimeImmutable('2026-05-27T13:00:00Z')));
$this->assertTrue($service->isExpired(newDateTimeImmutable('2026-05-27T11:00:00Z')));

Catalog

Each interface is narrow — one or a few related methods — so integrators can implement whatever subset their underlying library naturally covers. A single concrete class can implement many interfaces.

Clock and provider state

InterfaceMethodNotes
ClockStrategynow(): DateTimeImmutableExtends Psr\Clock\ClockInterface
HasTimezonegetTimezone(): DateTimeZonePlatform's configured timezone
HasLocalegetLocale(): stringPlatform's configured locale (BCP 47 / POSIX style)

Predicates on a single instant

InterfaceMethod
CanCheckIfPastisPast(DateTimeImmutable $instant): bool
CanCheckIfFutureisFuture(DateTimeImmutable $instant): bool
CanCheckIfWeekendisWeekend(DateTimeImmutable $instant): bool
CanCheckIfWeekdayisWeekday(DateTimeImmutable $instant): bool

Predicates on two instants

InterfaceMethod
CanCheckSameDayisSameDay(DateTimeImmutable $a, DateTimeImmutable $b): bool
CanCheckSameMonthisSameMonth(DateTimeImmutable $a, DateTimeImmutable $b): bool
CanCheckSameYearisSameYear(DateTimeImmutable $a, DateTimeImmutable $b): bool
CanCheckBetweenisBetween(DateTimeImmutable $i, DateTimeImmutable $start, DateTimeImmutable $end): bool

Arithmetic

InterfaceMethod
CanApplyModifierapply(DateTimeImmutable $instant, string $modifier): DateTimeImmutable
CanAddIntervaladd(DateTimeImmutable $instant, DateInterval $interval): DateTimeImmutable
CanSubtractIntervalsubtract(DateTimeImmutable $instant, DateInterval $interval): DateTimeImmutable

Calendar boundaries

InterfaceMethod
CanGetStartOfDaystartOfDay(DateTimeImmutable $instant): DateTimeImmutable
CanGetEndOfDayendOfDay(DateTimeImmutable $instant): DateTimeImmutable
CanGetStartOfMonthstartOfMonth(DateTimeImmutable $instant): DateTimeImmutable
CanGetEndOfMonthendOfMonth(DateTimeImmutable $instant): DateTimeImmutable
CanGetStartOfYearstartOfYear(DateTimeImmutable $instant): DateTimeImmutable
CanGetEndOfYearendOfYear(DateTimeImmutable $instant): DateTimeImmutable

Difference and duration

InterfaceMethod
CanGetDifferencediff(DateTimeImmutable $a, DateTimeImmutable $b): DateInterval
CanGetDifferenceInDaysdiffInDays(DateTimeImmutable $a, DateTimeImmutable $b): int
CanGetDifferenceInHoursdiffInHours(DateTimeImmutable $a, DateTimeImmutable $b): int
CanGetDifferenceInMinutesdiffInMinutes(DateTimeImmutable $a, DateTimeImmutable $b): int
CanGetDifferenceInSecondsdiffInSeconds(DateTimeImmutable $a, DateTimeImmutable $b): int

Parsing

InterfaceMethod
CanParseDateparse(string $expression): DateTimeImmutable
CanParseDateWithFormatparseFormat(string $expression, string $format): DateTimeImmutable

Formatting

InterfaceMethod
CanFormatDateformat(DateTimeImmutable $instant, string $format): string
CanFormatLocalizedDateformatLocalized(DateTimeImmutable $instant, string $format): string
CanFormatRelativeTimerelative(DateTimeImmutable $instant): string ("3 hours ago")

Model contracts

These two are model-side contracts for persisted records — every PHPNomad model that participates in audit trails implements them.

InterfaceMethod
HasCreatedDategetCreatedDate(): DateTimeImmutable
HasModifiedDategetModifiedDate(): DateTimeImmutable

How integrations compose the catalog

An integration package ships one or more concrete classes that implement the cluster of interfaces its underlying library can naturally fulfill. phpnomad/wordpress-integration ships a class implementing the WordPress-specific subset:

class WordPressClockStrategy implements
ClockStrategy,
HasTimezone,
CanFormatLocalizedDate,
CanFormatRelativeTime
{
publicfunctionnow(): DateTimeImmutable { /* current_datetime() */ }
publicfunctiongetTimezone(): DateTimeZone { /* wp_timezone() */ }
publicfunctionformatLocalized(DateTimeImmutable$i, string$f): string { /* wp_date() */ }
publicfunctionrelative(DateTimeImmutable$i): string { /* human_time_diff() */ }
}

A hypothetical phpnomad/carbon-integration would ship a class implementing the much broader Carbon-backed cluster (predicates, arithmetic, boundaries, diff, parsing, formatting). A consumer that needs WordPress's timezone alongside Carbon's diff math binds each interface to the appropriate concrete.

Why a catalog of narrow interfaces

A single fat TimeStrategy interface would force every integrator to implement methods their underlying library does not naturally support. A catalog of narrow interfaces lets integrators declare exactly what their library covers, and lets consumers depend only on the capabilities they use. Integrations declare PHPNomad support by implementing the relevant interfaces; consumers compose multiple integrations across libraries as needed.

License

MIT

About

Time-related contract interfaces for PHPNomad. Ships interfaces only — pair with a concrete integration package (e.g. wordpress-integration).

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages