Add format string for DateTime with timezone on SQLite - #7445
Conversation
|
@Roman3349, thank you for the patch. Please add tests. See Testing Guidelines for reference. |
cb72cb1 to
d0fd70d
Compare
|
@morozov I've added the tests. I'm sorry it took me so long - I did it right after I received your message, but then I had to deal with other things and forgot to commit the changes. |
|
Your test verifies that PHP parses a given date string correctly. It's good to know that PHP's date extension behaves as expected, but that's not the point of our test suite. We need a test that actually hits SQLite and makes sure that after your change, SQLite properly stores a date with timezone information and that the timezone is properly restored if we load a |
d0fd70d to
9c88a68
Compare
|
@derrabus For now, the Oracle tests will fail due to #6469/#2332. I should fix this at the platform level https://github.com/doctrine/dbal/blob/4.4.x/src/Platforms/OraclePlatform.php#L760-L763, where I would specify the format string |
derrabus
left a comment
There was a problem hiding this comment.
Thank you for the test. I've done some research because I found it hard to believe that we haven't covered this type already in our testsuite.
There is actually Doctrine\DBAL\Tests\Functional\TypeConversionTest::testIdempotentConversionToDateTime(). This test has a strange if block that basically skips most of the test for Types::DATETIMETZ_MUTABLE. I think, we should either fix that test or remove the Types::DATETIMETZ_MUTABLE case from it entirely. Also, Types::DATETIMETZ_IMMUTABLE apparently is not covered at all. We should probably fix that, too.
|
|
||
| final class DateTimeTzTest extends FunctionalTestCase | ||
| { | ||
| /** @return DateTimeInterface[][] */ |
There was a problem hiding this comment.
| /** @return DateTimeInterface[][] */ | |
| /** @return list<array{DateTime}> */ |
| } | ||
|
|
||
| #[DataProvider('dataValuesProvider')] | ||
| public function testInsertAndRetrieveDateTimeTz(DateTimeInterface $expected): void |
There was a problem hiding this comment.
| public function testInsertAndRetrieveDateTimeTz(DateTimeInterface $expected): void | |
| public function testInsertAndRetrieveDateTimeTz(DateTime $expected): void |
| $value = Type::getType(Types::DATETIMETZ_MUTABLE)->convertToPHPValue( | ||
| $this->connection->fetchOne('SELECT val FROM datetimetz_table'), | ||
| $platform, | ||
| ); |
There was a problem hiding this comment.
| $value = Type::getType(Types::DATETIMETZ_MUTABLE)->convertToPHPValue( | |
| $this->connection->fetchOne('SELECT val FROM datetimetz_table'), | |
| $platform, | |
| ); | |
| $value = $this->connection->convertToPHPValue( | |
| $this->connection->fetchOne('SELECT val FROM datetimetz_table'), | |
| Types::DATETIMETZ_MUTABLE, | |
| ); |
| public static function dataValuesProvider(): array | ||
| { | ||
| return [ | ||
| [new DateTime('1985-09-01 10:10:10')], |
There was a problem hiding this comment.
Given that the timezone is actually relevant here, we should not rely on PHP's default timezone. Let's add an explicit timezone here.
|
One more thing we have to think about. We're about to change the behavior of two types for SQLite. The old behavior might not have been the intended one, but still there might be apps out there that have configured that type on SQLite. What would happen if those apps upgraded to the new DBAL version with the new behavior? Would they still be able to read databases that were created with the old behavior? |
Signed-off-by: Roman Ondráček <mail@romanondracek.cz>
Signed-off-by: Roman Ondráček <mail@romanondracek.cz>
…pport saving DateTime with timezone info Signed-off-by: Roman Ondráček <mail@romanondracek.cz>
…n format string Signed-off-by: Roman Ondráček <mail@romanondracek.cz>
Signed-off-by: Roman Ondráček <mail@romanondracek.cz>
…r saving timezone offset Signed-off-by: Roman Ondráček <mail@romanondracek.cz>
beae1a2 to
eb9c69a
Compare
|
@derrabus Thank you for your review, your suggestions should now be addressed. For the existing stored values, I've added a fallback for the SQLite platform to parse values from the database, I couldn't come up with a better solution than do it in the type. The branch is now rebased to latest commit on |
|
I'm just not sure whether to leave the tests in their respective classes or put them in |
| } | ||
|
|
||
| // Fallback to DateTime format for SQLite to preserve compatibility with older versions of Doctrine DBAL | ||
| if ($platform instanceof SQLitePlatform) { |
There was a problem hiding this comment.
Never do instanceof checks on the platform. This code belongs into the platform class.
There was a problem hiding this comment.
So should I add a public constant or getter to AbstractPlatform to indicate that datetimetz can store a datetime? And this constant/getter will be set to true for SQLitePlatform.
Because otherwise, I can’t think of how to do this in the platform code, since the only relevant thing in the platform code is the format used. Everything else related to converting values from the DB to PHP happens in the class of the given type and in Doctrine\DBAL\Connection.
There was a problem hiding this comment.
The platforms are a collection of template methods that we call whenever we need a behavior to be different between database platforms.
So, when you find yourself doing something like this…
if ($platform instanceof FooPlatform) {
// behavior for the foo database
} else {
// default behavior
}… then you should always be able to refactor this block into a method on AbstractPlatform which is overridden on FooPlatform, so the whole if block collapses into…
$platform->someBehavior();Does that make sense?
Summary
Saves the timezone information for DateTimeTz type on SQLite3.
Information from the SQLite3 documentation