Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit c10a780

Browse filesBrowse files
committed
[Serializer] DateTimeNormalizer: allow to provide timezone
1 parent 08aa6a8 commit c10a780
Copy full SHA for c10a780

File tree

2 files changed

+106
-4
lines changed
Filter options

2 files changed

+106
-4
lines changed

‎src/Symfony/Component/Serializer/Normalizer/DateTimeNormalizer.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Serializer/Normalizer/DateTimeNormalizer.php
+30-4Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,18 +23,22 @@
2323
class DateTimeNormalizer implements NormalizerInterface, DenormalizerInterface
2424
{
2525
const FORMAT_KEY = 'datetime_format';
26+
const TIMEZONE_KEY = 'datetime_timezone';
2627

2728
/**
2829
* @var string
2930
*/
3031
private $format;
32+
private $timezone;
3133

3234
/**
33-
* @param string $format
35+
* @param string $format
36+
* @param \DateTimeZone|null $timezone
3437
*/
35-
public function __construct($format = \DateTime::RFC3339)
38+
public function __construct($format = \DateTime::RFC3339, \DateTimeZone $timezone = null)
3639
{
3740
$this->format = $format;
41+
$this->timezone = $timezone;
3842
}
3943

4044
/**
@@ -49,6 +53,11 @@ public function normalize($object, $format = null, array $context = array())
4953
}
5054

5155
$format = isset($context[self::FORMAT_KEY]) ? $context[self::FORMAT_KEY] : $this->format;
56+
$timezone = $this->getTimezone($context);
57+
58+
if (null !== $timezone) {
59+
$object = (new \DateTimeImmutable('@'.$object->getTimestamp()))->setTimezone($timezone);
60+
}
5261

5362
return $object->format($format);
5463
}
@@ -69,9 +78,15 @@ public function supportsNormalization($data, $format = null)
6978
public function denormalize($data, $class, $format = null, array $context = array())
7079
{
7180
$dateTimeFormat = isset($context[self::FORMAT_KEY]) ? $context[self::FORMAT_KEY] : null;
81+
$timezone = $this->getTimezone($context);
7282

7383
if (null !== $dateTimeFormat) {
74-
$object = \DateTime::class === $class ? \DateTime::createFromFormat($dateTimeFormat, $data) : \DateTimeImmutable::createFromFormat($dateTimeFormat, $data);
84+
if (null === $timezone && PHP_VERSION_ID < 50600) {
85+
// https://bugs.php.net/bug.php?id=68669
86+
$object = \DateTime::class === $class ? \DateTime::createFromFormat($dateTimeFormat, $data) : \DateTimeImmutable::createFromFormat($dateTimeFormat, $data);
87+
} else {
88+
$object = \DateTime::class === $class ? \DateTime::createFromFormat($dateTimeFormat, $data, $timezone) : \DateTimeImmutable::createFromFormat($dateTimeFormat, $data, $timezone);
89+
}
7590

7691
if (false !== $object) {
7792
return $object;
@@ -89,7 +104,7 @@ public function denormalize($data, $class, $format = null, array $context = arra
89104
}
90105

91106
try {
92-
return \DateTime::class === $class ? new \DateTime($data) : new \DateTimeImmutable($data);
107+
return \DateTime::class === $class ? new \DateTime($data, $timezone) : new \DateTimeImmutable($data, $timezone);
93108
} catch (\Exception $e) {
94109
throw new UnexpectedValueException($e->getMessage(), $e->getCode(), $e);
95110
}
@@ -126,4 +141,15 @@ private function formatDateTimeErrors(array $errors)
126141

127142
return $formattedErrors;
128143
}
144+
145+
private function getTimezone(array $context)
146+
{
147+
$dateTimeZone = array_key_exists(self::TIMEZONE_KEY, $context) ? $context[self::TIMEZONE_KEY] : $this->timezone;
148+
149+
if (null === $dateTimeZone) {
150+
return null;
151+
}
152+
153+
return $dateTimeZone instanceof \DateTimeZone ? $dateTimeZone : new \DateTimeZone($dateTimeZone);
154+
}
129155
}

‎src/Symfony/Component/Serializer/Tests/Normalizer/DateTimeNormalizerTest.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Serializer/Tests/Normalizer/DateTimeNormalizerTest.php
+76Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,32 @@ public function testNormalizeUsingFormatPassedInConstructor()
5252
$this->assertEquals('16', (new DateTimeNormalizer('y'))->normalize(new \DateTime('2016/01/01', new \DateTimeZone('UTC'))));
5353
}
5454

55+
public function testNormalizeUsingTimeZonePassedInConstructor()
56+
{
57+
$normalizer = new DateTimeNormalizer(\DateTime::RFC3339, new \DateTimeZone('Japan'));
58+
59+
$this->assertSame('2016-12-01T00:00:00+09:00', $normalizer->normalize(new \DateTime('2016/12/01', new \DateTimeZone('Japan'))));
60+
$this->assertSame('2016-12-01T09:00:00+09:00', $normalizer->normalize(new \DateTime('2016/12/01', new \DateTimeZone('UTC'))));
61+
}
62+
63+
/**
64+
* @dataProvider normalizeUsingTimeZonePassedInContextProvider
65+
*/
66+
public function testNormalizeUsingTimeZonePassedInContext($expected, $input, $timezone)
67+
{
68+
$this->assertSame($expected, $this->normalizer->normalize($input, null, array(
69+
DateTimeNormalizer::TIMEZONE_KEY => $timezone,
70+
)));
71+
}
72+
73+
public function normalizeUsingTimeZonePassedInContextProvider()
74+
{
75+
yield array('2016-12-01T00:00:00+00:00', new \DateTime('2016/12/01', new \DateTimeZone('UTC')), null);
76+
yield array('2016-12-01T00:00:00+09:00', new \DateTime('2016/12/01', new \DateTimeZone('Japan')), new \DateTimeZone('Japan'));
77+
yield array('2016-12-01T09:00:00+09:00', new \DateTime('2016/12/01', new \DateTimeZone('UTC')), new \DateTimeZone('Japan'));
78+
yield array('2016-12-01T09:00:00+09:00', new \DateTimeImmutable('2016/12/01', new \DateTimeZone('UTC')), new \DateTimeZone('Japan'));
79+
}
80+
5581
/**
5682
* @expectedException \Symfony\Component\Serializer\Exception\InvalidArgumentException
5783
* @expectedExceptionMessage The object must implement the "\DateTimeInterface".
@@ -76,13 +102,63 @@ public function testDenormalize()
76102
$this->assertEquals(new \DateTime('2016/01/01', new \DateTimeZone('UTC')), $this->normalizer->denormalize('2016-01-01T00:00:00+00:00', \DateTime::class));
77103
}
78104

105+
public function testDenormalizeUsingTimezonePassedInConstructor()
106+
{
107+
$timezone = new \DateTimeZone('Japan');
108+
$expected = new \DateTime('2016/12/01 17:35:00', $timezone);
109+
$normalizer = new DateTimeNormalizer(null, $timezone);
110+
111+
$this->assertEquals($expected, $normalizer->denormalize('2016.12.01 17:35:00', \DateTime::class, null, array(
112+
DateTimeNormalizer::FORMAT_KEY => 'Y.m.d H:i:s',
113+
)));
114+
}
115+
79116
public function testDenormalizeUsingFormatPassedInContext()
80117
{
81118
$this->assertEquals(new \DateTimeImmutable('2016/01/01'), $this->normalizer->denormalize('2016.01.01', \DateTimeInterface::class, null, array(DateTimeNormalizer::FORMAT_KEY => 'Y.m.d|')));
82119
$this->assertEquals(new \DateTimeImmutable('2016/01/01'), $this->normalizer->denormalize('2016.01.01', \DateTimeImmutable::class, null, array(DateTimeNormalizer::FORMAT_KEY => 'Y.m.d|')));
83120
$this->assertEquals(new \DateTime('2016/01/01'), $this->normalizer->denormalize('2016.01.01', \DateTime::class, null, array(DateTimeNormalizer::FORMAT_KEY => 'Y.m.d|')));
84121
}
85122

123+
/**
124+
* @dataProvider denormalizeUsingTimezonePassedInContextProvider
125+
*/
126+
public function testDenormalizeUsingTimezonePassedInContext($input, $expected, $timezone, $format = null)
127+
{
128+
$actual = $this->normalizer->denormalize($input, \DateTimeInterface::class, null, array(
129+
DateTimeNormalizer::TIMEZONE_KEY => $timezone,
130+
DateTimeNormalizer::FORMAT_KEY => $format,
131+
));
132+
133+
$this->assertEquals($expected, $actual);
134+
}
135+
136+
public function denormalizeUsingTimezonePassedInContextProvider()
137+
{
138+
yield 'with timezone' => array(
139+
'2016/12/01 17:35:00',
140+
new \DateTimeImmutable('2016/12/01 17:35:00', new \DateTimeZone('Japan')),
141+
new \DateTimeZone('Japan'),
142+
);
143+
yield 'with timezone as string' => array(
144+
'2016/12/01 17:35:00',
145+
new \DateTimeImmutable('2016/12/01 17:35:00', new \DateTimeZone('Japan')),
146+
'Japan',
147+
);
148+
yield 'with format without timezone information' => array(
149+
'2016.12.01 17:35:00',
150+
new \DateTimeImmutable('2016/12/01 17:35:00', new \DateTimeZone('Japan')),
151+
new \DateTimeZone('Japan'),
152+
'Y.m.d H:i:s',
153+
);
154+
yield 'ignored with format with timezone information' => array(
155+
'2016-12-01T17:35:00Z',
156+
new \DateTimeImmutable('2016/12/01 17:35:00', new \DateTimeZone('UTC')),
157+
'Europe/Paris',
158+
\DateTime::RFC3339,
159+
);
160+
}
161+
86162
/**
87163
* @expectedException \Symfony\Component\Serializer\Exception\UnexpectedValueException
88164
*/

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.