Datetime
Overview
PHP provides multiple date and time implementations. There is DateTime
and DateTimeImmutable
, based on DateTimeInterface
, as well as IntlCalendar
. Unfortunately, those implementation have rough, low-level, awkward APIs, which are not pleasant to work with.
Tempest provides an alternative to DateTimeInterface
, partially based on IntlCalendar
. This implementation provides a better API with a more consistent interface. It was initially created by @azjezz for the PSL, and was ported to Tempest so it could be deeply integrated.
Creating date instances
The Tempest\DateTime\DateTime
class provides a DateTime::parse()
method to create a date from a string, a timestamp, or another datetime instance. This is the most flexible way to create a date instance.
DateTime::parse('2025-09-19 02:00:00');
Alternatively, if you know the format of the date string you are working with, you may use the DateTime::fromPattern()
. It accepts a standard ICU format.
Finally, for more specific use cases, the DateTime::fromString()
method may be used to create a date from a localized date and time string.
For the current date and time
The recommended approach for getting the current time is by calling the now()
method on the Tempest\Clock\Clock
interface, which may be injected as a dependency in any class.
However, for convenience, you may also create a DateTime
instance for the current time using the DateTime::now()
method or the Tempest\now()
function.
$now = DateTime::now();
From a known format pattern
If you know the format of the date string you are working with, you should prefer using the DateTime::fromPattern()
method. It accepts a standard ICU format.
DateTime::fromPattern('2025-09-19 02:00', pattern: 'yyyy-MM-dd HH:mm');
Manipulating dates
The DateTime
class provides multiple methods to manipulate dates. You may add or subtract time from a date using the plus()
and minus()
methods, which accept a Duration
instance.
For convenience, more specific manipulation methods are also provided.
// Adding a set duration $date->plus(Duration::seconds(30)); // Using convenience methods $date->plusHour(); $date->plusMinutes(30); $date->minusDay(); $date->endOfDay();
Converting timezones
All datetime creation methods accept a timezone
parameter. This parameter accepts an instance of the Timezone
enumeration. When not provided, the default timezone, provided by date.timezone
, will be used.
You may convert the timezone of an existing instance by calling the convertToTimezone()
method:
use Tempest\DateTime\DateTime; use Tempest\DateTime\Timezone; $date = DateTime::now(); $date->convertToTimezone(Timezone::EUROPE_PARIS);
Computing a duration
By calling the between()
method on a date instance, you may compute the duration between this date and a second one. This method returns a Duration
instance.
use Tempest\DateTime\DateTime; $date1 = DateTime::now(); $date2 = DateTime::parse('2025-09-19 02:00:00'); $duration = $date1->between($date2);
Comparing dates
The DateTime
instance provides multiple methods to compare dates against each other, or against the current time. For instance, you may check if a date is before or after another date using the isBefore()
and isAfter()
methods, respectively.
// Check if a date is before another date, inclusively $date->isBefore($other); // Check if a date is before another date, exclusively $date->isBeforeOrAtTheSameTime($other); // Check if a date between two other dates, inclusively $date->betweenTimeInclusive($otherDate1, $otherDate2); // Check if a date is in the future $date->isFuture();
Formatting dates
You may format a DateTime
instance in a specific format using the format()
method. This method accepts an optional format string, which is a standard ICU format, and an optional locale.
use Tempest\DateTime\FormatPattern; use Tempest\DateTime\Locale; $date->format(); // 19 Sept 2025, 02:00:00 $date->format(pattern: FormatPattern::COOKIE); // Monday, 19-Sept-2025 02:00:00 BST $date->format(locale: Locale::FRENCH); // 19 sept. 2025, 02:00:00
Clock interface
Tempest provides a Tempest\Clock\Clock
interface which may be injected as a dependency in any class. This is the recommended way of working with time.
final readonly class HomeController { public function __construct( private readonly Clock $clock, ) {} public function __invoke(): View { return view('./home.view.php', currentTime: $this->clock->now()); } }
Note that because Tempest has its own DateTime
implementation, the Clock
interface is not compatible with PSR-20. However, you may get a PSR-20 implementation by calling the toPsrClock()
method.
$psrClock = $clock->toPsrClock();
Testing time
Tempest provides a time-related testing utilities accessible through the clock
method of the IntegrationTest
test case.
Calling this method replaces the Clock
instance in the container with a testing one, on which a specific date and time can be defined. DateTime
instances created with the DateTime::now()
method or Tempest\now()
function will use the date and time specified by the testing clock.
// Create a testing clock $clock = $this->clock(); // Set a specific date and time $clock->setNow('2025-09-19 02:00:00'); // Advance time by the specified duration $clock->sleep(milliseconds: 250);