8000 Add timezone to param converter · symfony/symfony@b07747f · GitHub
[go: up one dir, main page]

Skip to content

Commit b07747f

Browse files
committed
Add timezone to param converter
1 parent e6e7efd commit b07747f

File tree

3 files changed

+101
-16
lines changed

3 files changed

+101
-16
lines changed

src/Symfony/Component/HttpKernel/Attribute/MapDateTime.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,8 @@
1818
class MapDateTime
1919
{
2020
public function __construct(
21-
public readonly ?string $format = null
21+
public readonly ?string $format = null,
22+
public readonly ?string $timezone = null,
2223
) {
2324
}
2425
}

src/Symfony/Component/HttpKernel/Controller/ArgumentResolver/DateTimeValueResolver.php

Lines changed: 21 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -48,30 +48,42 @@ public function resolve(Request $request, ArgumentMetadata $argument): iterable
4848

4949
$class = \DateTimeInterface::class === $argument->getType() ? \DateTimeImmutable::class : $argument->getType();
5050
$format = null;
51+
$timezone = null;
5152

5253
if ($attributes = $argument->getAttributes(MapDateTime::class, ArgumentMetadata::IS_INSTANCEOF)) {
5354
$attribute = $attributes[0];
5455
$format = $attribute->format;
56+
$timezone = $attribute->timezone;
5557
}
5658

5759
$date = false;
60+
$defaultTimezone = date_default_timezone_get();
61+
if ('default' === $timezone) {
62+
$timezone = $defaultTimezone;
63+
} elseif ($timezone) {
64+
date_default_timezone_set($timezone);
65+
}
5866

59-
if (null !== $format) {
60-
$date = $class::createFromFormat($format, $value);
67+
try {
68+
if (null !== $format) {
69+
$date = $class::createFromFormat($format, $value);
6170

62-
if ($class::getLastErrors()['warning_count']) {
63-
$date = false;
71+
if ($class::getLastErrors()['warning_count']) {
72+
$date = false;
73+
}
74+
} elseif (false !== filter_var($value, \FILTER_VALIDATE_INT, ['options' => ['min_range' => 0]])) {
75+
$date = new $class('@'.$value);
76+
} elseif (false !== $timestamp = strtotime($value)) {
77+
$date = new $class('@'.$timestamp);
6478
}
65-
} elseif (false !== filter_var($value, \FILTER_VALIDATE_INT, ['options' => ['min_range' => 0]])) {
66-
$date = new $class('@'.$value);
67-
} elseif (false !== $timestamp = strtotime($value)) {
68-
$date = new $class('@'.$timestamp);
79+
} finally {
80+
date_default_timezone_set($defaultTimezone);
6981
}
7082

7183
if (!$date) {
7284
throw new NotFoundHttpException(sprintf('Invalid date given for parameter "%s".', $argument->getName()));
7385
}
7486

75-
yield $date;
87+
yield $timezone ? $date->setTimezone(new \DateTimeZone($timezone)) : $date;
7688
}
7789
}

src/Symfony/Component/HttpKernel/Tests/Controller/ArgumentResolver/DateTimeValueResolverTest.php

Lines changed: 78 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -65,15 +65,16 @@ public function testFullDate(string $timezone)
6565
$resolver = new DateTimeValueResolver();
6666

6767
$argument = new ArgumentMetadata('dummy', \DateTime::class, false, false, null);
68-
$request = self::requestWithAttributes(['dummy' => '2012-07-21 00:00:00+0000']);
68+
$request = self::requestWithAttributes(['dummy' => '2012-07-21 00:00:00 +05:00']);
6969

7070
/** @var \Generator $results */
7171
$results = $resolver->resolve($request, $argument);
7272
$results = iterator_to_array($results);
7373

7474
$this->assertCount(1, $results);
7575
$this->assertInstanceOf(\DateTime::class, $results[0]);
76-
$this->assertEquals('2012-07-21', $results[0]->format('Y-m-d'));
76+
$this->assertSame('+00:00', $results[0]->getTimezone()->getName());
77+
$this->assertEquals('2012-07-20 19:00:00', $results[0]->format('Y-m-d H:i:s'));
7778
}
7879

7980
/**
@@ -93,6 +94,7 @@ public function testUnixTimestamp(string $timezone)
9394

9495
$this->assertCount(1, $results);
9596
$this->assertInstanceOf(\DateTime::class, $results[0]);
97+
$this->assertSame('+00:00', $results[0]->getTimezone()->getName());
9698
$this->assertEquals('2001-05-11', $results[0]->format('Y-m-d'));
9799
}
98100

@@ -113,19 +115,20 @@ public function testNullableWithEmptyAttribute()
113115

114116
public function testCustomClass()
115117
{
116-
date_default_timezone_set('UTC');
118+
date_default_timezone_set('Etc/GMT+9');
117119
$resolver = new DateTimeValueResolver();
118120

119121
$argument = new ArgumentMetadata('dummy', FooDateTime::class, false, false, null);
120-
$request = self::requestWithAttributes(['dummy' => '2016-09-08 00:00:00']);
122+
$request = self::requestWithAttributes(['dummy' => '2016-09-08 00:00:00 -04:00']);
121123

122124
/** @var \Generator $results */
123125
$results = $resolver->resolve($request, $argument);
124126
$results = iterator_to_array($results);
125127

126128
$this->assertCount(1, $results);
127129
$this->assertInstanceOf(FooDateTime::class, $results[0]);
128-
$this->assertEquals('2016-09-08', $results[0]->format('Y-m-d'));
130+
$this->assertSame('+00:00', $results[0]->getTimezone()->getName());
131+
$this->assertEquals('2016-09-08 04:00:00', $results[0]->format('Y-m-d H:i:s'));
129132
}
130133

131134
/**
@@ -145,15 +148,84 @@ public function testDateTimeImmutable(string $timezone)
145148

146149
$this->assertCount(1, $results);
147150
$this->assertInstanceOf(\DateTimeImmutable::class, $results[0]);
151+
$this->assertSame('+00:00', $results[0]->getTimezone()->getName());
148152
$this->assertEquals('2016-09-08', $results[0]->format('Y-m-d'));
149153
}
150154

155+
/**
156+
* @dataProvider getTimeZones
157+
*/
158+
public function testWithFormat(string $timezone)
159+
{
160+
date_default_timezone_set($timezone);
161+
$resolver = new DateTimeValueResolver();
162+
163+
$argument = new ArgumentMetadata('dummy', \DateTimeInterface::class, false, false, null, false, [
164+
MapDateTime::class => new MapDateTime('m-d-y H:i:s'),
165+
]);
166+
$request = self::requestWithAttributes(['dummy' => '09-08-16 12:34:56']);
167+
168+
/** @var \Generator $results */
169+
$results = $resolver->resolve($request, $argument);
170+
$results = iterator_to_array($results);
171+
172+
$this->assertCount(1, $results);
173+
$this->assertInstanceOf(\DateTimeImmutable::class, $results[0]);
174+
$this->assertSame($timezone, $results[0]->getTimezone()->getName());
175+
$this->assertEquals('2016-09-08 12:34:56', $results[0]->format('Y-m-d H:i:s'));
176+
}
177+
178+
/**
179+
* @dataProvider getTimeZones
180+
*/
181+
public function testWithTimezone(string $timezone)
182+
{
183+
date_default_timezone_set($timezone);
184+
$resolver = new DateTimeValueResolver();
185+
186+
$argument = new ArgumentMetadata('dummy', \DateTimeInterface::class, false, false, null, false, [
187+
MapDateTime::class => new MapDateTime(null, 'Antarctica/Troll'),
188+
]);
189+
$request = self::requestWithAttributes(['dummy' => '2016-09-08 12:34:56']);
190+
191+
/** @var \Generator $results */
192+
$results = $resolver->resolve($request, $argument);
193+
$results = iterator_to_array($results);
194+
195+
$this->assertCount(1, $results);
196+
$this->assertInstanceOf(\DateTimeImmutable::class, $results[0]);
197+
$this->assertSame('Antarctica/Troll', $results[0]->getTimezone()->getName());
198+
$this->assertEquals('2016-09-08 12:34:56 +02:00', $results[0]->format('Y-m-d H:i:s P'));
199+
}
200+
201+
/**
202+
* @dataProvider getTimeZones
203+
*/
204+
public function testWithFormatAndTimezone(string $timezone)
205+
{
206+
date_default_timezone_set($timezone);
207+
$resolver = new DateTimeValueResolver();
208+
209+
$argument = new ArgumentMetadata('dummy', \DateTimeInterface::class, false, false, null, false, [
210+
MapDateTime::class => new MapDateTime('m-d-y H:i:s', 'Antarctica/Troll'),
211+
]);
212+
$request = self::requestWithAttributes(['dummy' => '09-08-16 12:34:56']);
213+
214+
/** @var \Generator $results */
215+
$results = $resolver->resolve($request, $argument);
216+
$results = iterator_to_array($results);
217+
218+
$this->assertCount(1, $results);
219+
$this->assertInstanceOf(\DateTimeImmutable::class, $results[0]);
220+
$this->assertEquals('2016-09-08 12:34:56 +02:00', $results[0]->format('Y-m-d H:i:s P'));
221+
}
222+
151223
public function provideInvalidDates()
152224
{
153225
return [
154226
'invalid date' => [
155227
new ArgumentMetadata('dummy', \DateTime::class, false, false, null),
156-
self::requestWithAttributes(['dummy' => 'Invalid DateTime Format'])
228+
self::requestWithAttributes(['dummy' => 'Invalid DateTime Format']),
157229
],
158230
'invalid format' => [
159231
new ArgumentMetadata('dummy', \DateTime::class, false, false, null, false, [new MapDateTime(format: 'd.m.Y')]),

0 commit comments

Comments
 (0)
0