[Serializer] DateTimeNormalizer: allow to provide timezone
This commit is contained in:
parent
08aa6a8582
commit
c10a780afb
@ -23,18 +23,22 @@ use Symfony\Component\Serializer\Exception\UnexpectedValueException;
|
||||
class DateTimeNormalizer implements NormalizerInterface, DenormalizerInterface
|
||||
{
|
||||
const FORMAT_KEY = 'datetime_format';
|
||||
const TIMEZONE_KEY = 'datetime_timezone';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $format;
|
||||
private $timezone;
|
||||
|
||||
/**
|
||||
* @param string $format
|
||||
* @param string $format
|
||||
* @param \DateTimeZone|null $timezone
|
||||
*/
|
||||
public function __construct($format = \DateTime::RFC3339)
|
||||
public function __construct($format = \DateTime::RFC3339, \DateTimeZone $timezone = null)
|
||||
{
|
||||
$this->format = $format;
|
||||
$this->timezone = $timezone;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -49,6 +53,11 @@ class DateTimeNormalizer implements NormalizerInterface, DenormalizerInterface
|
||||
}
|
||||
|
||||
$format = isset($context[self::FORMAT_KEY]) ? $context[self::FORMAT_KEY] : $this->format;
|
||||
$timezone = $this->getTimezone($context);
|
||||
|
||||
if (null !== $timezone) {
|
||||
$object = (new \DateTimeImmutable('@'.$object->getTimestamp()))->setTimezone($timezone);
|
||||
}
|
||||
|
||||
return $object->format($format);
|
||||
}
|
||||
@ -69,9 +78,15 @@ class DateTimeNormalizer implements NormalizerInterface, DenormalizerInterface
|
||||
public function denormalize($data, $class, $format = null, array $context = array())
|
||||
{
|
||||
$dateTimeFormat = isset($context[self::FORMAT_KEY]) ? $context[self::FORMAT_KEY] : null;
|
||||
$timezone = $this->getTimezone($context);
|
||||
|
||||
if (null !== $dateTimeFormat) {
|
||||
$object = \DateTime::class === $class ? \DateTime::createFromFormat($dateTimeFormat, $data) : \DateTimeImmutable::createFromFormat($dateTimeFormat, $data);
|
||||
if (null === $timezone && PHP_VERSION_ID < 50600) {
|
||||
// https://bugs.php.net/bug.php?id=68669
|
||||
$object = \DateTime::class === $class ? \DateTime::createFromFormat($dateTimeFormat, $data) : \DateTimeImmutable::createFromFormat($dateTimeFormat, $data);
|
||||
} else {
|
||||
$object = \DateTime::class === $class ? \DateTime::createFromFormat($dateTimeFormat, $data, $timezone) : \DateTimeImmutable::createFromFormat($dateTimeFormat, $data, $timezone);
|
||||
}
|
||||
|
||||
if (false !== $object) {
|
||||
return $object;
|
||||
@ -89,7 +104,7 @@ class DateTimeNormalizer implements NormalizerInterface, DenormalizerInterface
|
||||
}
|
||||
|
||||
try {
|
||||
return \DateTime::class === $class ? new \DateTime($data) : new \DateTimeImmutable($data);
|
||||
return \DateTime::class === $class ? new \DateTime($data, $timezone) : new \DateTimeImmutable($data, $timezone);
|
||||
} catch (\Exception $e) {
|
||||
throw new UnexpectedValueException($e->getMessage(), $e->getCode(), $e);
|
||||
}
|
||||
@ -126,4 +141,15 @@ class DateTimeNormalizer implements NormalizerInterface, DenormalizerInterface
|
||||
|
||||
return $formattedErrors;
|
||||
}
|
||||
|
||||
private function getTimezone(array $context)
|
||||
{
|
||||
$dateTimeZone = array_key_exists(self::TIMEZONE_KEY, $context) ? $context[self::TIMEZONE_KEY] : $this->timezone;
|
||||
|
||||
if (null === $dateTimeZone) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $dateTimeZone instanceof \DateTimeZone ? $dateTimeZone : new \DateTimeZone($dateTimeZone);
|
||||
}
|
||||
}
|
||||
|
@ -52,6 +52,32 @@ class DateTimeNormalizerTest extends TestCase
|
||||
$this->assertEquals('16', (new DateTimeNormalizer('y'))->normalize(new \DateTime('2016/01/01', new \DateTimeZone('UTC'))));
|
||||
}
|
||||
|
||||
public function testNormalizeUsingTimeZonePassedInConstructor()
|
||||
{
|
||||
$normalizer = new DateTimeNormalizer(\DateTime::RFC3339, new \DateTimeZone('Japan'));
|
||||
|
||||
$this->assertSame('2016-12-01T00:00:00+09:00', $normalizer->normalize(new \DateTime('2016/12/01', new \DateTimeZone('Japan'))));
|
||||
$this->assertSame('2016-12-01T09:00:00+09:00', $normalizer->normalize(new \DateTime('2016/12/01', new \DateTimeZone('UTC'))));
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider normalizeUsingTimeZonePassedInContextProvider
|
||||
*/
|
||||
public function testNormalizeUsingTimeZonePassedInContext($expected, $input, $timezone)
|
||||
{
|
||||
$this->assertSame($expected, $this->normalizer->normalize($input, null, array(
|
||||
DateTimeNormalizer::TIMEZONE_KEY => $timezone,
|
||||
)));
|
||||
}
|
||||
|
||||
public function normalizeUsingTimeZonePassedInContextProvider()
|
||||
{
|
||||
yield array('2016-12-01T00:00:00+00:00', new \DateTime('2016/12/01', new \DateTimeZone('UTC')), null);
|
||||
yield array('2016-12-01T00:00:00+09:00', new \DateTime('2016/12/01', new \DateTimeZone('Japan')), new \DateTimeZone('Japan'));
|
||||
yield array('2016-12-01T09:00:00+09:00', new \DateTime('2016/12/01', new \DateTimeZone('UTC')), new \DateTimeZone('Japan'));
|
||||
yield array('2016-12-01T09:00:00+09:00', new \DateTimeImmutable('2016/12/01', new \DateTimeZone('UTC')), new \DateTimeZone('Japan'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \Symfony\Component\Serializer\Exception\InvalidArgumentException
|
||||
* @expectedExceptionMessage The object must implement the "\DateTimeInterface".
|
||||
@ -76,6 +102,17 @@ class DateTimeNormalizerTest extends TestCase
|
||||
$this->assertEquals(new \DateTime('2016/01/01', new \DateTimeZone('UTC')), $this->normalizer->denormalize('2016-01-01T00:00:00+00:00', \DateTime::class));
|
||||
}
|
||||
|
||||
public function testDenormalizeUsingTimezonePassedInConstructor()
|
||||
{
|
||||
$timezone = new \DateTimeZone('Japan');
|
||||
$expected = new \DateTime('2016/12/01 17:35:00', $timezone);
|
||||
$normalizer = new DateTimeNormalizer(null, $timezone);
|
||||
|
||||
$this->assertEquals($expected, $normalizer->denormalize('2016.12.01 17:35:00', \DateTime::class, null, array(
|
||||
DateTimeNormalizer::FORMAT_KEY => 'Y.m.d H:i:s',
|
||||
)));
|
||||
}
|
||||
|
||||
public function testDenormalizeUsingFormatPassedInContext()
|
||||
{
|
||||
$this->assertEquals(new \DateTimeImmutable('2016/01/01'), $this->normalizer->denormalize('2016.01.01', \DateTimeInterface::class, null, array(DateTimeNormalizer::FORMAT_KEY => 'Y.m.d|')));
|
||||
@ -83,6 +120,45 @@ class DateTimeNormalizerTest extends TestCase
|
||||
$this->assertEquals(new \DateTime('2016/01/01'), $this->normalizer->denormalize('2016.01.01', \DateTime::class, null, array(DateTimeNormalizer::FORMAT_KEY => 'Y.m.d|')));
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider denormalizeUsingTimezonePassedInContextProvider
|
||||
*/
|
||||
public function testDenormalizeUsingTimezonePassedInContext($input, $expected, $timezone, $format = null)
|
||||
{
|
||||
$actual = $this->normalizer->denormalize($input, \DateTimeInterface::class, null, array(
|
||||
DateTimeNormalizer::TIMEZONE_KEY => $timezone,
|
||||
DateTimeNormalizer::FORMAT_KEY => $format,
|
||||
));
|
||||
|
||||
$this->assertEquals($expected, $actual);
|
||||
}
|
||||
|
||||
public function denormalizeUsingTimezonePassedInContextProvider()
|
||||
{
|
||||
yield 'with timezone' => array(
|
||||
'2016/12/01 17:35:00',
|
||||
new \DateTimeImmutable('2016/12/01 17:35:00', new \DateTimeZone('Japan')),
|
||||
new \DateTimeZone('Japan'),
|
||||
);
|
||||
yield 'with timezone as string' => array(
|
||||
'2016/12/01 17:35:00',
|
||||
new \DateTimeImmutable('2016/12/01 17:35:00', new \DateTimeZone('Japan')),
|
||||
'Japan',
|
||||
);
|
||||
yield 'with format without timezone information' => array(
|
||||
'2016.12.01 17:35:00',
|
||||
new \DateTimeImmutable('2016/12/01 17:35:00', new \DateTimeZone('Japan')),
|
||||
new \DateTimeZone('Japan'),
|
||||
'Y.m.d H:i:s',
|
||||
);
|
||||
yield 'ignored with format with timezone information' => array(
|
||||
'2016-12-01T17:35:00Z',
|
||||
new \DateTimeImmutable('2016/12/01 17:35:00', new \DateTimeZone('UTC')),
|
||||
'Europe/Paris',
|
||||
\DateTime::RFC3339,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \Symfony\Component\Serializer\Exception\UnexpectedValueException
|
||||
*/
|
||||
|
Reference in New Issue
Block a user