Skip to content

Commit 021916e

Browse files
committed
Deprecate passing timezone information to methods where it is ignored
1 parent b158403 commit 021916e

File tree

2 files changed

+143
-4
lines changed

2 files changed

+143
-4
lines changed

src/Types/DateImmutableType.php

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,22 @@ public function convertToDatabaseValue($value, AbstractPlatform $platform)
3535
}
3636

3737
if ($value instanceof DateTimeImmutable) {
38+
$offset = $value->format('O');
39+
$defaultOffset = (new DateTimeImmutable())->format('O');
40+
41+
if ($offset !== $defaultOffset) {
42+
Deprecation::triggerIfCalledFromOutside(
43+
'doctrine/dbal',
44+
'https://github.com/doctrine/dbal/pull/6020',
45+
'Passing a timezone offset (%s) different than the default one (%s) is deprecated'
46+
. ' as it will be lost, use %s::%s() instead.',
47+
$offset,
48+
$defaultOffset,
49+
DateTimeTzImmutableType::class,
50+
__FUNCTION__,
51+
);
52+
}
53+
3854
return $value->format($platform->getDateFormatString());
3955
}
4056

@@ -56,7 +72,27 @@ public function convertToDatabaseValue($value, AbstractPlatform $platform)
5672
*/
5773
public function convertToPHPValue($value, AbstractPlatform $platform)
5874
{
59-
if ($value === null || $value instanceof DateTimeImmutable) {
75+
if ($value === null) {
76+
return null;
77+
}
78+
79+
if ($value instanceof DateTimeImmutable) {
80+
$offset = $value->format('O');
81+
$defaultOffset = (new DateTimeImmutable())->format('O');
82+
83+
if ($offset !== $defaultOffset) {
84+
Deprecation::triggerIfCalledFromOutside(
85+
'doctrine/dbal',
86+
'https://github.com/doctrine/dbal/pull/6020',
87+
'Passing a timezone offset (%s) different than the default one (%s) is deprecated'
88+
. ' as it may be lost, use %s::%s() instead.',
89+
$offset,
90+
$defaultOffset,
91+
DateTimeTzImmutableType::class,
92+
__FUNCTION__,
93+
);
94+
}
95+
6096
return $value;
6197
}
6298

tests/Types/DateImmutableTypeTest.php

Lines changed: 106 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,17 +4,22 @@
44

55
use DateTime;
66
use DateTimeImmutable;
7+
use DateTimeZone;
78
use Doctrine\DBAL\ParameterType;
89
use Doctrine\DBAL\Platforms\AbstractPlatform;
910
use Doctrine\DBAL\Types\ConversionException;
1011
use Doctrine\DBAL\Types\DateImmutableType;
12+
use Doctrine\Deprecations\PHPUnit\VerifyDeprecations;
13+
use InvalidArgumentException;
1114
use PHPUnit\Framework\MockObject\MockObject;
1215
use PHPUnit\Framework\TestCase;
1316

1417
use function get_class;
1518

1619
class DateImmutableTypeTest extends TestCase
1720
{
21+
use VerifyDeprecations;
22+
1823
/** @var AbstractPlatform&MockObject */
1924
private AbstractPlatform $platform;
2025

@@ -48,10 +53,18 @@ public function testConvertsDateTimeImmutableInstanceToDatabaseValue(): void
4853
$this->platform->expects(self::once())
4954
->method('getDateFormatString')
5055
->willReturn('Y-m-d');
51-
$date->expects(self::once())
56+
$date->expects(self::exactly(2))
5257
->method('format')
53-
->with('Y-m-d')
54-
->willReturn('2016-01-01');
58+
->willReturnCallback(static function (string $format): string {
59+
switch ($format) {
60+
case 'O':
61+
return 'UTC';
62+
case 'Y-m-d':
63+
return '2016-01-01';
64+
default:
65+
throw new InvalidArgumentException();
66+
}
67+
});
5568

5669
self::assertSame(
5770
'2016-01-01',
@@ -117,4 +130,94 @@ public function testRequiresSQLCommentHint(): void
117130
{
118131
self::assertTrue($this->type->requiresSQLCommentHint($this->platform));
119132
}
133+
134+
/** @dataProvider provideDateTimeInstancesWithTimezone */
135+
public function testTimezoneDeprecationFromConvertsToDatabaseValue(string $defaultTimeZone, DateTimeImmutable $date): void
136+
{
137+
$this->iniSet('date.timezone', $defaultTimeZone);
138+
139+
$defaultOffset = (new DateTimeImmutable())->format('O');
140+
141+
self::assertFalse($defaultOffset === $date->format('O'));
142+
143+
$this->platform->expects(self::once())
144+
->method('getDateFormatString')
145+
->willReturn('Y-m-d');
146+
147+
$this->expectDeprecationWithIdentifier('https://github.com/doctrine/dbal/pull/6020');
148+
149+
$this->type->convertToDatabaseValue($date, $this->platform);
150+
}
151+
152+
/** @dataProvider provideDateTimeInstancesWithTimezone */
153+
public function testTimezoneDeprecationFromConvertToPHPValue(string $defaultTimeZone, DateTimeImmutable $date): void
154+
{
155+
$this->iniSet('date.timezone', $defaultTimeZone);
156+
157+
$defaultOffset = (new DateTimeImmutable())->format('O');
158+
159+
self::assertFalse($defaultOffset === $date->format('O'));
160+
161+
$this->expectDeprecationWithIdentifier('https://github.com/doctrine/dbal/pull/6020');
162+
163+
$this->type->convertToPHPValue($date, $this->platform);
164+
}
165+
166+
/** @psalm-return iterable<string, array{0: string, 1: DateTimeImmutable}> */
167+
public function provideDateTimeInstancesWithTimezone(): iterable
168+
{
169+
yield 'timezone_utc' => [
170+
'UTC',
171+
(new DateTimeImmutable())->setTimezone(new DateTimeZone('America/Argentina/Buenos_Aires')),
172+
];
173+
174+
yield 'timezone_amsterdam' => [
175+
'Europe/Amsterdam',
176+
(new DateTimeImmutable())->setTimezone(new DateTimeZone('America/Argentina/Buenos_Aires')),
177+
];
178+
179+
yield 'offset_utc' => [
180+
'UTC',
181+
(new DateTimeImmutable())->setTimezone(new DateTimeZone('-0300')),
182+
];
183+
}
184+
185+
/** @dataProvider provideDateTimeInstancesWithNoTimezoneDiff */
186+
public function testNoTimezoneInValueConversion(string $defaultTimeZone, DateTimeImmutable $date): void
187+
{
188+
$this->iniSet('date.timezone', $defaultTimeZone);
189+
190+
$this->platform->expects(self::once())
191+
->method('getDateFormatString')
192+
->willReturn('Y-m-d');
193+
194+
$this->expectNoDeprecationWithIdentifier('https://github.com/doctrine/dbal/pull/6020');
195+
196+
$this->type->convertToDatabaseValue($date, $this->platform);
197+
$this->type->convertToPHPValue($date, $this->platform);
198+
}
199+
200+
/** @psalm-return iterable<string, array{0: string, 1: DateTimeImmutable}> */
201+
public function provideDateTimeInstancesWithNoTimezoneDiff(): iterable
202+
{
203+
yield 'timezone_utc' => [
204+
'UTC',
205+
(new DateTimeImmutable())->setTimezone(new DateTimeZone('UTC')),
206+
];
207+
208+
yield 'timezone_buenos_aires' => [
209+
'America/Argentina/Buenos_Aires',
210+
(new DateTimeImmutable())->setTimezone(new DateTimeZone('America/Argentina/Buenos_Aires')),
211+
];
212+
213+
yield 'same_offset_with_different_timezones' => [
214+
'America/Sao_Paulo',
215+
(new DateTimeImmutable())->setTimezone(new DateTimeZone('America/Argentina/Buenos_Aires')),
216+
];
217+
218+
yield 'offset_-0300' => [
219+
'America/Argentina/Buenos_Aires',
220+
(new DateTimeImmutable())->setTimezone(new DateTimeZone('-0300')),
221+
];
222+
}
120223
}

0 commit comments

Comments
 (0)