Brick\DateTime
, (*1)
A powerful set of immutable classes to work with dates and times., (*2)
, (*3)
Introduction
This library builds an extensive API on top of the native PHP date-time classes, and adds missing concepts such as LocalDate
, LocalTime
, YearMonth
, MonthDay
, etc., (*4)
The classes follow the ISO 8601 standard for representing date and time concepts., (*5)
This component follows an important part of the JSR 310 (Date and Time API) specification from Java.
Don't expect an exact match of class and method names though, as a number of differences exist for technical or practical reasons., (*6)
All the classes are immutable, they can be safely passed around without being affected., (*7)
Installation
This library is installable via Composer:, (*8)
composer require brick/date-time
Requirements
This library requires PHP 8.1 or later., (*9)
Project status & release process
While this library is still under development, it is well tested and should be stable enough to use in production environments., (*10)
The current releases are numbered 0.x.y
. When a non-breaking change is introduced (adding new methods, optimizing existing code, etc.), y
is incremented., (*11)
When a breaking change is introduced, a new 0.x
version cycle is always started., (*12)
It is therefore safe to lock your project to a given release cycle, such as 0.7.*
., (*13)
If you need to upgrade to a newer release cycle, check the release history for a list of changes introduced by each further 0.x.0
version., (*14)
Overview
Main classes
The following classes/enums represent the date-time concepts:, (*15)
-
DayOfWeek
: a day-of-week such as Monday (enum
)
-
Duration
: a duration measured in seconds and nanoseconds
-
Instant
: a point in time, with a nanosecond precision
-
Interval
: a period of time between two instants
-
LocalDate
: an isolated date such as 2014-08-31
-
LocalDateRange
: an inclusive range of local dates, such as 2014-01-01/2014-12-31
-
LocalDateTime
: a date-time without a time-zone, such as 2014-08-31T10:15:30
-
LocalTime
: an isolated time such as 10:15:30
-
Month
: a month-of-year such as January (enum
)
-
MonthDay
: a combination of a month and a day, without a year, such as --12-31
-
Period
: a date-based amount of time, such as '2 years, 3 months and 4 days'
-
TimeZoneOffset
: an offset-based time-zone, such as +01:00
-
TimeZoneRegion
: a region-based time-zone, such as Europe/London
-
Year
: a year in the proleptic calendar
-
YearMonth
: a combination of a year and a month, such as 2014-08
-
ZonedDateTime
: a date-time with a time-zone, such as 2014-08-31T10:15:30+01:00
.
This class is conceptually equivalent to the native DateTime
class
These classes belong to the Brick\DateTime
namespace., (*16)
Clocks
All objects read the current time from a Clock
implementation. The following implementations are available:, (*17)
-
SystemClock
returns the system time; it's the default clock
-
FixedClock
: returns a pre-configured time
-
OffsetClock
: adds an offset to another clock
-
ScaleClock
: makes another clock fast-forward by a scale factor
These classes belong to the Brick\DateTime\Clock
namespace., (*18)
In your application, you will most likely never touch the defaults, and always use the default clock:, (*19)
use Brick\DateTime\LocalDate;
use Brick\DateTime\TimeZone;
echo LocalDate::now(TimeZone::utc()); // 2017-10-04
In your tests however, you might need to set the current time to test your application in known conditions. To do this, you can either explicitly pass a Clock
instance to now()
methods:, (*20)
use Brick\DateTime\Clock\FixedClock;
use Brick\DateTime\Instant;
use Brick\DateTime\LocalDate;
use Brick\DateTime\TimeZone;
$clock = new FixedClock(Instant::of(1000000000));
echo LocalDate::now(TimeZone::utc(), $clock); // 2001-09-09
Or you can change the default clock for all date-time classes. All methods such as now()
, unless provided with an explicit Clock, will use the default clock you provide:, (*21)
use Brick\DateTime\Clock\FixedClock;
use Brick\DateTime\DefaultClock;
use Brick\DateTime\Instant;
use Brick\DateTime\LocalDate;
use Brick\DateTime\TimeZone;
DefaultClock::set(new FixedClock(Instant::of(1000000000)));
echo LocalDate::now(TimeZone::utc()); // 2001-09-09
DefaultClock::reset(); // do not forget to reset the clock to the system clock!
There are also useful shortcut methods to use clocks in your tests, inspired by timecop:, (*22)
-
freeze()
freezes time to a specific point in time
-
travelTo()
travels to an Instant
in time, but allows time to continue moving forward from there
-
travelBy()
travels in time by a Duration
, which may be forward (positive) or backward (negative)
-
scale()
makes time move at a given pace
Freeze the time to a specific point
use Brick\DateTime\DefaultClock;
use Brick\DateTime\Instant;
DefaultClock::freeze(Instant::of(2000000000));
$a = Instant::now(); sleep(1);
$b = Instant::now();
echo $a, PHP_EOL; // 2033-05-18T03:33:20Z
echo $b, PHP_EOL; // 2033-05-18T03:33:20Z
DefaultClock::reset();
Travel to a specific point in time
use Brick\DateTime\DefaultClock;
use Brick\DateTime\Instant;
DefaultClock::travelTo(Instant::of(2000000000));
$a = Instant::now(); sleep(1);
$b = Instant::now();
echo $a, PHP_EOL; // 2033-05-18T03:33:20.000342Z
echo $b, PHP_EOL; // 2033-05-18T03:33:21.000606Z
DefaultClock::reset();
Make time move at a given pace
use Brick\DateTime\DefaultClock;
use Brick\DateTime\Instant;
DefaultClock::travelTo(Instant::of(2000000000));
DefaultClock::scale(60); // 1 second becomes 60 seconds
$a = Instant::now(); sleep(1);
$b = Instant::now();
echo $a, PHP_EOL; // 2033-05-18T03:33:20.00188Z
echo $b, PHP_EOL; // 2033-05-18T03:34:20.06632Z
DefaultClock::reset();
As you can see, you can even combine travelTo()
and scale()
methods., (*23)
Be very careful to reset()
the DefaultClock after each of your tests! If you're using PHPUnit, a good place to do this is in the tearDown()
method., (*24)
Exceptions
The following exceptions can be thrown:, (*25)
-
Brick\DateTime\DateTimeException
when an illegal operation is performed
-
Brick\DateTime\Parser\DateTimeParseException
when parse()
ing an invalid string representation
Doctrine mappings
You can use brick/date-time
types in your Doctrine entities using the brick/date-time-doctrine package., (*26)
Contributing
Before submitting a pull request, you can check the code using the following tools.
Your CI build will fail if any of the following tools reports any issue., (*27)
First of all, install dependencies:, (*28)
composer install
Unit tests
Run PHPUnit tests:, (*29)
vendor/bin/phpunit
Static analysis
Install Psalm in its own folder:, (*30)
composer install --working-dir=tools/psalm
Run Psalm static analysis:, (*31)
tools/psalm/vendor/bin/psalm --no-cache --config=tools/psalm/psalm.xml
Coding Style
Install Easy Coding Standard in its own folder:, (*32)
composer install --working-dir=tools/ecs
Run coding style analysis checks:, (*33)
tools/ecs/vendor/bin/ecs check --config tools/ecs/ecs.php
Or fix issues found directly:, (*34)
tools/ecs/vendor/bin/ecs check --config tools/ecs/ecs.php --fix
Rector automated refactoring
Install Rector in its own folder:, (*35)
composer install --working-dir=tools/rector
Run automated refactoring:, (*36)
tools/rector/vendor/bin/rector --config tools/rector/rector.php