Features

Datetime

Tempest provides a complete alternative to the DateTime implementation, with a higher-level API, deeply integrated into the framework.

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);