Skip to content
developed by

Dates and intervals

Default value conversion

Per default, any \DateTime or \DateTimeImmutable PHP objects given as values will be converted to timestamp (also known as datetime in some vendors) SQL values (with time zone transparently handled if significant):

php
$expr = $queryBuilder->expression();

$queryBuilder
    ->select()
    ->column(
        $expr->value(new \DateTimeImmutable())
    )
    ->executeQuery()
    ->fetchOne()
;

// Or

$queryBuilder
    ->raw('select ?', [new \DateTimeImmutable()])
    ->executeQuery()
    ->fetchOne()
;

Will both return a value such as: 2024-03-14 13:44:32.456298+00 (precision and offset depends upon the database vendor).

Current timestamp

The current_timestamp SQL expression may vary depending upon database vendor, a specific expression is available for portability:

php
$expr = $queryBuilder->expression();

$queryBuilder
    ->select()
    ->column(
        $expr->currentTimestamp()
    )
    ->executeQuery()
    ->fetchOne()
;

Which should return a value such as: 2024-03-14 13:44:32.456298+00 (precision and offset depends upon the database vendor).

TIP

You may choose to create a MakinaCorpus\QueryBuilder\Expression\CurrentTimestamp instance manually instead, without using the factory.

Casting to date

If you require an SQL date value instead of a timestamp, you can cast your values:

php
$expr = $queryBuilder->expression();

$queryBuilder
    ->select()
    ->column(
        $expr->cast(
            new \DateTimeImmutable(),
            'date'
        )
    )
    ->executeQuery()
    ->fetchOne()
;

// Or

$queryBuilder
    ->raw('select cast(? as date)', [new \DateTimeImmutable()])
    ->executeQuery()
    ->fetchOne()
;

Will both return a value such as: 2024-03-14.

Interval expressions

The SQL interval type is only supported by PostgreSQL at the time being, for all other vendors, intervals are materialized via function parameters or using a custom dialect instead.

WARNING

You can create MakinaCorpus\QueryBuilder\Expression\DateInterval or MakinaCorpus\QueryBuilder\Expression\DateIntervalUnit expressions, but don't attempt to format those arbitrarily outside of date operator or function, it won't work and write invalid SQL most of the cases.

Do not manually use interval related expressions outside of data operators and functions.

Interval values

TIP

In opposition to the previous statement, PostgreSQL is the only database vendor known to handle interval as a type and able to use interval values outside of date functions.

This mean you can use the interval type as a column type, or in value type casts when using PostgreSQL.

You can type values passed to the query builder using the interval type which will convert the values to an ISO interval string, for example, all of the following queries being semantically equivalent:

php
$expr = $queryBuilder->expression();

$interval = \DateInterval::createFromDateString('1 hour 2 minutes');

$queryBuilder->raw('select ?', [$interval]);
$queryBuilder->raw('select interval ?', ['1 hour 2 minutes']);
$queryBuilder->raw('select cast(? as interval)', ['1 hour 2 minutes']);
$queryBuilder->raw('select interval ?', [$interval]);
$queryBuilder->raw('select ?', [$expr->cast($interval, 'interval')]);
$queryBuilder->raw('select ?', [$expr->value($interval, 'interval')]);

Date add, date sub

You may use the MakinaCorpus\QueryBuilder\Expression\DateAdd and MakinaCorpus\QueryBuilder\Expression\DateSub to add or substract interval to dates.

All the following examples are semantically equivalent:

php
$queryBuilder
    ->select()
    ->column(
        $expr->dateAdd(
            $expr->currentTimestamp(),
            '1 hour 2 minutes',
        )
    )
;

// Or

$queryBuilder
    ->select()
    ->column(
        $expr->dateAdd(
            $expr->currentTimestamp(),
            'PT1H2M',
        )
    )
;

// Or

$queryBuilder
    ->select()
    ->column(
        $expr->dateAdd(
            $expr->currentTimestamp(),
            [
                'hour' => 1,
                'minute' => 2,
            ],
        )
    )
;

// Or

$queryBuilder
    ->select()
    ->column(
        $expr->dateAdd(
            $expr->currentTimestamp(),
            new \DateInterval('PT1H2M'),
        )
    )
;

Date substraction has the exact same signature.

You may also provide interval value using an arbitrary expression, which must return an integer typed value, for example:

php
$queryBuilder
    ->select()
    ->column(
        $expr->dateAdd(
            $expr->currentTimestamp(),
            $expr->intervalUnit(
                $expr->raw('(select ?)', [12]),
                'hour'
            ),
        )
    )
;

Hydrating SQL dates to PHP

Simply use the row instance instead of using a raw result:

php
$value = $queryBuilder
    ->raw('select cast(? as date)', [new \DateTimeImmutable()])
    ->executeQuery()
    ->fetchRow()
    ->get(0, \DateTimeImmutable::class)
;

The returned $value will be an instance \DateTimeImmutable.

INFO

Time zone will be handled gracefully, since when using a timestamp with time zone, most vendors will simply store the UTC value, the hydrator will behave accordingly, set the UTC time zone at object creation, then convert it to the current default PHP time zone.

TIP

You can also hydrate \DateTime instances. If you choose \DateTimeInterface instead, a \DateTimeImmutable will be hydrated.