Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit e848729

Browse files
committed
bug #33066 [Serializer] Fix negative DateInterval (jderusse)
This PR was merged into the 3.4 branch. Discussion ---------- [Serializer] Fix negative DateInterval | Q | A | ------------- | --- | Branch? | 3.4 | Bug fix? | yes | New feature? | no | BC breaks? | no | Deprecations? | no | Tests pass? | yes | Fixed tickets | #33052 | License | MIT | Doc PR | NA This PR adds support for negative and signed DateInterval Commits ------- abb8a67 Fix negative DateInterval
2 parents 7afc935 + abb8a67 commit e848729

File tree

2 files changed

+50
-7
lines changed

2 files changed

+50
-7
lines changed

src/Symfony/Component/Serializer/Normalizer/DateIntervalNormalizer.php

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ class DateIntervalNormalizer implements NormalizerInterface, DenormalizerInterfa
2929
/**
3030
* @param string $format
3131
*/
32-
public function __construct($format = 'P%yY%mM%dDT%hH%iM%sS')
32+
public function __construct($format = '%rP%yY%mM%dDT%hH%iM%sS')
3333
{
3434
$this->format = $format;
3535
}
@@ -76,12 +76,34 @@ public function denormalize($data, $class, $format = null, array $context = [])
7676

7777
$dateIntervalFormat = isset($context[self::FORMAT_KEY]) ? $context[self::FORMAT_KEY] : $this->format;
7878

79-
$valuePattern = '/^'.preg_replace('/%([yYmMdDhHiIsSwW])(\w)/', '(?P<$1>\d+)$2', $dateIntervalFormat).'$/';
79+
$signPattern = '';
80+
switch (substr($dateIntervalFormat, 0, 2)) {
81+
case '%R':
82+
$signPattern = '[-+]';
83+
$dateIntervalFormat = substr($dateIntervalFormat, 2);
84+
break;
85+
case '%r':
86+
$signPattern = '-?';
87+
$dateIntervalFormat = substr($dateIntervalFormat, 2);
88+
break;
89+
}
90+
$valuePattern = '/^'.$signPattern.preg_replace('/%([yYmMdDhHiIsSwW])(\w)/', '(?P<$1>\d+)$2', $dateIntervalFormat).'$/';
8091
if (!preg_match($valuePattern, $data)) {
8192
throw new UnexpectedValueException(sprintf('Value "%s" contains intervals not accepted by format "%s".', $data, $dateIntervalFormat));
8293
}
8394

8495
try {
96+
if ('-' === $data[0]) {
97+
$interval = new \DateInterval(substr($data, 1));
98+
$interval->invert = 1;
99+
100+
return $interval;
101+
}
102+
103+
if ('+' === $data[0]) {
104+
return new \DateInterval(substr($data, 1));
105+
}
106+
85107
return new \DateInterval($data);
86108
} catch (\Exception $e) {
87109
throw new UnexpectedValueException($e->getMessage(), $e->getCode(), $e);
@@ -98,6 +120,6 @@ public function supportsDenormalization($data, $type, $format = null)
98120

99121
private function isISO8601($string)
100122
{
101-
return preg_match('/^P(?=\w*(?:\d|%\w))(?:\d+Y|%[yY]Y)?(?:\d+M|%[mM]M)?(?:(?:\d+D|%[dD]D)|(?:\d+W|%[wW]W))?(?:T(?:\d+H|[hH]H)?(?:\d+M|[iI]M)?(?:\d+S|[sS]S)?)?$/', $string);
123+
return preg_match('/^[\-+]?P(?=\w*(?:\d|%\w))(?:\d+Y|%[yY]Y)?(?:\d+M|%[mM]M)?(?:(?:\d+D|%[dD]D)|(?:\d+W|%[wW]W))?(?:T(?:\d+H|[hH]H)?(?:\d+M|[iI]M)?(?:\d+S|[sS]S)?)?$/', $string);
102124
}
103125
}

src/Symfony/Component/Serializer/Tests/Normalizer/DateIntervalNormalizerTest.php

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,11 @@ public function dataProviderISO()
2929
['P%yY%mM%dDT%hH%iM', 'P10Y2M3DT16H5M', 'P10Y2M3DT16H5M'],
3030
['P%yY%mM%dDT%hH', 'P10Y2M3DT16H', 'P10Y2M3DT16H'],
3131
['P%yY%mM%dD', 'P10Y2M3D', 'P10Y2M3DT0H'],
32+
['%RP%yY%mM%dD', '-P10Y2M3D', '-P10Y2M3DT0H'],
33+
['%RP%yY%mM%dD', '+P10Y2M3D', '+P10Y2M3DT0H'],
34+
['%RP%yY%mM%dD', '+P10Y2M3D', 'P10Y2M3DT0H'],
35+
['%rP%yY%mM%dD', '-P10Y2M3D', '-P10Y2M3DT0H'],
36+
['%rP%yY%mM%dD', 'P10Y2M3D', 'P10Y2M3DT0H'],
3237
];
3338

3439
return $data;
@@ -50,15 +55,15 @@ public function testNormalize()
5055
*/
5156
public function testNormalizeUsingFormatPassedInContext($format, $output, $input)
5257
{
53-
$this->assertEquals($output, $this->normalizer->normalize(new \DateInterval($input), null, [DateIntervalNormalizer::FORMAT_KEY => $format]));
58+
$this->assertEquals($output, $this->normalizer->normalize($this->getInterval($input), null, [DateIntervalNormalizer::FORMAT_KEY => $format]));
5459
}
5560

5661
/**
5762
* @dataProvider dataProviderISO
5863
*/
5964
public function testNormalizeUsingFormatPassedInConstructor($format, $output, $input)
6065
{
61-
$this->assertEquals($output, (new DateIntervalNormalizer($format))->normalize(new \DateInterval($input)));
66+
$this->assertEquals($output, (new DateIntervalNormalizer($format))->normalize($this->getInterval($input)));
6267
}
6368

6469
public function testNormalizeInvalidObjectThrowsException()
@@ -84,15 +89,15 @@ public function testDenormalize()
8489
*/
8590
public function testDenormalizeUsingFormatPassedInContext($format, $input, $output)
8691
{
87-
$this->assertDateIntervalEquals(new \DateInterval($output), $this->normalizer->denormalize($input, \DateInterval::class, null, [DateIntervalNormalizer::FORMAT_KEY => $format]));
92+
$this->assertDateIntervalEquals($this->getInterval($input), $this->normalizer->denormalize($input, \DateInterval::class, null, [DateIntervalNormalizer::FORMAT_KEY => $format]));
8893
}
8994

9095
/**
9196
* @dataProvider dataProviderISO
9297
*/
9398
public function testDenormalizeUsingFormatPassedInConstructor($format, $input, $output)
9499
{
95-
$this->assertDateIntervalEquals(new \DateInterval($output), (new DateIntervalNormalizer($format))->denormalize($input, \DateInterval::class));
100+
$this->assertDateIntervalEquals($this->getInterval($input), (new DateIntervalNormalizer($format))->denormalize($input, \DateInterval::class));
96101
}
97102

98103
public function testDenormalizeExpectsString()
@@ -124,4 +129,20 @@ private function assertDateIntervalEquals(\DateInterval $expected, \DateInterval
124129
{
125130
$this->assertEquals($expected->format('%RP%yY%mM%dDT%hH%iM%sS'), $actual->format('%RP%yY%mM%dDT%hH%iM%sS'));
126131
}
132+
133+
private function getInterval($data)
134+
{
135+
if ('-' === $data[0]) {
136+
$interval = new \DateInterval(substr($data, 1));
137+
$interval->invert = 1;
138+
139+
return $interval;
140+
}
141+
142+
if ('+' === $data[0]) {
143+
return new \DateInterval(substr($data, 1));
144+
}
145+
146+
return new \DateInterval($data);
147+
}
127148
}

0 commit comments

Comments
 (0)