alex-patterson-webdev / date-time
DateTime factory components for PHP
Installs: 1 447
Dependents: 3
Suggesters: 0
Security: 0
Stars: 1
Watchers: 2
Forks: 0
Open Issues: 1
Requires
- php: >=8.1
- psr/clock: ^1.0.0
Requires (Dev)
- friendsofphp/php-cs-fixer: ^3.6.0
- phpspec/prophecy: ^1.15.0
- phpstan/phpstan: ^1.4.8
- phpunit/phpunit: ^9.5
- squizlabs/php_codesniffer: ^3.6
Provides
This package is auto-updated.
Last update: 2024-12-06 16:57:22 UTC
README
Arp\DateTime
About
The library provides implementations of the PSR-20 Clock ClockInterface
and a
number of factories which abstract the creation of native PHP DateTime objects.
Installation
Installation via composer.
require alex-patterson-webdev/date-time ^0.6
Theory
By abstracting the creation of Date Time objects behind a simple collection of interfaces, we can allow developers to treat date time creation as a service.
The Arp\DateTime\DateTimeFactory
can be used as a replacement for any code that would normally require new \DateTime()
.
Consider an example UserService::updateLastLoginDate()
method; designed to update a user's last login date with the current date and time.
class UserService
{
public function updateLastLoginDate($user)
{
$user->setLastLoginDate(new \DateTime());
}
}
This approach, while simple, would be difficult to assert a value for the 'current time' in a unit test. Alternatively, we could update this
example to include the DateTimeFactory
, which would abstract the creation of the \DateTime
object.
class UserService
{
private DateTimeFactoryInterface $dateTimeFactory;
public function __construct(DateTimeFactoryInterface $dateTimeFactory)
{
$this->dateTimeFactory = $dateTimeFactory;
}
public function updateLastLoginDate($user)
{
$user->setLastLoginDate($this->dateTimeFactory->createDateTime());
}
}
The approach has a number of notable benefits
- The
DateTimeFactoryInterface
provides an abstraction for all\DateTime
object creation. - Unit testing and asserting date time values becomes very easy as we can now mock the return value of
$this->dateTimeFactory->createDateTime()
. - Rather than returning a boolean
false
when unable to create date objects, the factory classes will instead throw aDateTimeException
.
DateTimeFactoryInterface
The DateTimeFactoryInterface
exposes two public methods, createDateTime()
and createFromFormat()
. The method signatures are
similar to the PHP \DateTime
methods.
interface DateTimeFactoryInterface
{
/**
* @throws DateTimeFactoryException
*/
public function createDateTime(?string $spec = null, $timeZone = null): \DateTimeInterface;
/**
* @throws DateTimeFactoryException
*/
public function createFromFormat(string $format, string $spec, $timeZone = null): \DateTimeInterface;
}
The createDateTime()
method can replace uses of \DateTime::__construct.
The createFromFormat()
method can replace uses of \DateTime::createFromFormat().
There are however a number of differences to consider.
- The methods of the interface are defined as non-static and require a factory instance to invoke them.
- A
DateTimeFactoryException
will be thrown if the\DateTime
instance cannot be created. - The
$spec
parameter ofcreateDateTime()
acceptsnull
. Passingnull
is equivalent to using the current date and time, i.e.now
. - The
$timeZone
can be either astring
or\DateTimeZone
instance. If a supportedDateTimeZone
string is provided, the\DateTimeZone
instance will be created internally; otherwise aDateTimeFactoryException
will be thrown.
Implementations
The package provides two default implementations of the DateTimeFactoryInterface
.
DateTimeFactory
can be used to create\DateTime
instances.DateTimeImmutableFactory
can be used to create\DateTimeImmutible
instances
Because both classes implement the DateTimeFactoryInterface
, they can be used in the same way.
$dateTimeFactory = new \Arp\DateTime\DateTimeFactory();
$dateTimeImmutableFactory = new \Arp\DateTime\DateTimeImmutableFactory();
try {
/** @var \DateTime $dateTime **/
$dateTime = $dateTimeFactory->createDateTime();
/** @var \DateTimeImmutable $dateTimeImmutable **/
$dateTimeImmutable = $dateTimeImmutableFactory->createDateTime();
} catch (\DateTimeFactoryException $e) {
// if the date creation fails
}
DateTimeZoneFactory
\DateTimeZone
instances can be created using any class that implements Arp\DateTime\DateTimeZoneFactoryInterface
.
/*
* @throws DateTimeZoneFactoryException
*/
public function createDateTimeZone(string $spec): \DateTimeZone;
The default implementation of the interface is Arp\DateTime\DateTimeZoneFactory
.
$dateTimeZoneFactory = new \Arp\DateTime\DateTimeZoneFactory();
try {
/** @var \DateTimeZone $dateTimeZone **/
$dateTimeZone = $dateTimeZoneFactory->createDateTimeZone('UTC');
} catch (\DateTimeZoneFactoryException $e) {
// The \DateTimeZone() could not be created
}
PSR-20 ClockInterface
Using the PSR standards provides implementing projects interoperability between other packages by creating a standard way of accessing the current time.
The package provides a number of implementations of the PSR-20 Clock interface.
Arp\DateTime\Psr\Clock
A default implementation ofPsr\Clock\ClockInterface
where a desired DateTimeZone can be provided.Arp\DateTime\Psr\SystemClock
An implementation ofPsr\Clock\ClockInterface
that will always provide the current time using the configured system timezone.Arp\DateTime\Psr\FixedClock
An implementation ofPsr\Clock\ClockInterface
that will always return a fixed\DateTimeImmutable
; which can be useful in testing.
Example usages
use Arp\DateTime\DateTimeImmutableFactory;
use Arp\DateTime\Psr\SystemClock;
// Fetch the current time using the UTC timezone
$clock = new Clock(new DateTimeImmutableFactory(), 'UTC');
$utcTime = $clock->now();
// Fetch the current time using the systems configured timezone
$clock = new SystemClock(new DateTimeImmutableFactory());
$systemTime = $clock->now();
// Calls to FixedClock::now() will always return the same time provided in the constructor
$clock = new FixedClock(new \DateTimeImmutable());
$fixedTime = $clock->now();
Unit tests
Unit tests can be executed using PHPUnit from the application root directory.
php vendor/bin/phpunit