dbal icon indicating copy to clipboard operation
dbal copied to clipboard

Support precision option in datetime types (PostgreSQL)

Open upyx opened this issue 11 months ago • 5 comments

Q A
Type feature
Fixed issues #2873 #6631
Refers #5961

Summary

The year was 2025... I made yet another try to add support of microseconds to date-time types.

Looks like a really big work on #5961 is abandoned. Sadly. I've reviewed this PR. I think it modifies too many things and attempts to add microseconds everywhere. It reminds me of PHP 6 in trying to add support for Unicode globally.

Let's make things easy!

What it does

It adds to PostgreSQL platform support of microseconds for the next types:

  • DateTimeType
  • DateTimeImmutableType
  • DateTimeTzType
  • DateTimeImmutableTzType

To configure precision (in PostgreSQL documentation it calls "precision," not "scale") of those types, the precision option is available. For backward compatibility, the default precision is zero.

Additionally, it respects precision in schema introspection (fix #6631). In order to distinguish timestamp (without precision) and timestamp(6) the without_precision platform option was added.

VarDateTimeType and VarDateTimeImmutableType

According to description of these types, DateTime::__construct() twice slower then DateTime::createFromFormat(). I cannot remember the times when it was true. In my tests on PHP 8.1 (which is a lower supported version for 4.x), the constructor is slightly faster.

Script:

$i = 1000000;
while ($i--) {
    $dates[] = date('Y-m-d H:i:s.', random_int(0, 2 << 30)) . random_int(0, 999999);
}

echo end($dates) . PHP_EOL;
echo reset($dates) . PHP_EOL;

$startTime = hrtime(true);
foreach ($dates as $date) {
    $d = new DateTimeImmutable($date);
}

echo hrtime(true) - $startTime, ' ns', PHP_EOL;

$startTime = hrtime(true);
foreach ($dates as $date) {
    $d = DateTimeImmutable::createFromFormat('Y-m-d H:i:s.u', $date);
}

echo hrtime(true) - $startTime, ' ns', PHP_EOL;

Result:

2029-07-14 20:51:46.103511
1990-10-19 13:16:13.771286
2021394668 ns
2206943091 ns

What's next

  • [ ] Discuss the PR
  • [ ] Add other platforms
  • [ ] Fix bugs & add more tests

upyx avatar Jan 27 '25 21:01 upyx

In order to distinguish timestamp (without precision) and timestamp(6) the without_precision platform option was added.

Why is this distinction necessary? Not only that the type always has precision (whether it's specified explicitly or not), it makes it possible to specify both precision and without_precision on a column (or omit both), which makes no sense.

When the column definition defined by the application and containing without_precision is compared with the one introspected from the database, how should this comparison work?

morozov avatar Jan 28 '25 20:01 morozov

Why is this distinction necessary?

Because PostgreSQL does it. Column type can be altered from timestamp to timestamp(6) and vice versa (e.g. by schema:diff). So we need a way to save that differecne on introspection. And we can't use precision: null because it is already used for timestamp(0).

So the mapping here:

DBAL PostgreSQL
precision: null, without_precision: null timestamp(0)
precision: 0, without_precision: null timestamp(0)
precision: 6, without_precision: null timestamp(6)
precision: null, without_precision: true timestamp
precision: 0, without_precision: true timestamp
precision: 42, without_precision: true timestamp

Maybe that awkwardness was the reason why in #5961 used a scale property instead of presicion - the scale default is zero. I think it will be best to use "scale". What do you think?

upyx avatar Jan 29 '25 12:01 upyx

Because PostgreSQL does it.

In my understanding, the difference between timestamp and timestamp(6) is purely syntactic. The default precision is 6.

CREATE TABLE test_timestamps (
  ts1 TIMESTAMP,
  ts2 TIMESTAMP(6)
);

SELECT
  column_name,
  datetime_precision
FROM information_schema.columns
WHERE table_name = 'test_timestamps';

The above query will produce 6 for both columns.

Column type can be altered from timestamp to timestamp(6) and vice versa

They shouldn't be considered different. If they are, it's a bug.

Or, more specifically, the default precision of timestamp columns in DBAL is undefined, that's why they may produce a diff. But the point is, this issue needs to be addressed by improving the type system and type comparison logic, not introducing extra type parameters.

morozov avatar Jan 29 '25 18:01 morozov

There hasn't been any activity on this pull request in the past 90 days, so it has been marked as stale and it will be closed automatically if no further activity occurs in the next 7 days. If you want to continue working on it, please leave a comment.

github-actions[bot] avatar May 04 '25 03:05 github-actions[bot]

Despite the CS, the PR is green. What prevent this to be merged?

sukei avatar May 07 '25 18:05 sukei

There hasn't been any activity on this pull request in the past 90 days, so it has been marked as stale and it will be closed automatically if no further activity occurs in the next 7 days. If you want to continue working on it, please leave a comment.

github-actions[bot] avatar Oct 09 '25 03:10 github-actions[bot]

This pull request was closed due to inactivity.

github-actions[bot] avatar Oct 16 '25 03:10 github-actions[bot]