Date and time library
A powerful set of immutable classes to work with dates and times.
This library builds an extensive API on top of the native PHP date-time classes, and adds missing concepts such as
The classes follow the ISO 8601 standard for representing date and time concepts.
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.
All the classes are immutable, they can be safely passed around without being affected.
This library is installable via Composer:
composer require brick/date-time
This library requires PHP 7.4 or later.
While this library is still under development, it is well tested and should be stable enough to use in production environments.
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.
When a breaking change is introduced, a new
0.x version cycle is always started.
It is therefore safe to lock your project to a given release cycle, such as
If you need to upgrade to a newer release cycle, check the release history for a list of changes introduced by each further
The following classes represent the date-time concepts:
DayOfWeek: a day-of-week such as Monday
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
LocalDateRange: an inclusive range of local dates, such as
LocalDateTime: a date-time without a time-zone, such as
LocalTime: an isolated time such as
Month: a month-of-year such as January
MonthDay: a combination of a month and a day, without a year, such as
Period: a date-based amount of time, such as '2 years, 3 months and 4 days'
TimeZoneOffset: an offset-based time-zone, such as
TimeZoneRegion: a region-based time-zone, such as
Year: a year in the proleptic calendar
YearMonth: a combination of a year and a month, such as
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
These classes belong to the
All objects read the current time from a
Clock implementation. The following implementations are available:
SystemClockreturns 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
In your application, you will most likely never touch the defaults, and always use the default clock:
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
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:
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:
freeze()freezes time to a specific point in time
travel()travels to a specific point in time, but allows time to continue moving forward from there
scale()makes time move at a given pace
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();
use Brick\DateTime\DefaultClock; use Brick\DateTime\Instant; DefaultClock::travel(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();
use Brick\DateTime\DefaultClock; use Brick\DateTime\Instant; DefaultClock::travel(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
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
The following exceptions can be thrown:
Brick\DateTime\DateTimeExceptionwhen an illegal operation is performed
parse()ing an invalid string representation
You can use
brick/date-time types in your Doctrine entities using the brick/date-time-doctrine package.
Install Easy Coding Standard tool in its own folder
composer install --working-dir=tools/ecs
Run coding style analysis checks
./tools/ecs/vendor/bin/ecs check --config tools/ecs/ecs.php
Or fix issues found directly
./tools/ecs/vendor/bin/ecs check --config tools/ecs/ecs.php --fix