Fix negative DateInterval
This commit is contained in:
parent
889f454f93
commit
abb8a676ba
@ -29,7 +29,7 @@ class DateIntervalNormalizer implements NormalizerInterface, DenormalizerInterfa
|
|||||||
/**
|
/**
|
||||||
* @param string $format
|
* @param string $format
|
||||||
*/
|
*/
|
||||||
public function __construct($format = 'P%yY%mM%dDT%hH%iM%sS')
|
public function __construct($format = '%rP%yY%mM%dDT%hH%iM%sS')
|
||||||
{
|
{
|
||||||
$this->format = $format;
|
$this->format = $format;
|
||||||
}
|
}
|
||||||
@ -76,12 +76,34 @@ class DateIntervalNormalizer implements NormalizerInterface, DenormalizerInterfa
|
|||||||
|
|
||||||
$dateIntervalFormat = isset($context[self::FORMAT_KEY]) ? $context[self::FORMAT_KEY] : $this->format;
|
$dateIntervalFormat = isset($context[self::FORMAT_KEY]) ? $context[self::FORMAT_KEY] : $this->format;
|
||||||
|
|
||||||
$valuePattern = '/^'.preg_replace('/%([yYmMdDhHiIsSwW])(\w)/', '(?P<$1>\d+)$2', $dateIntervalFormat).'$/';
|
$signPattern = '';
|
||||||
|
switch (substr($dateIntervalFormat, 0, 2)) {
|
||||||
|
case '%R':
|
||||||
|
$signPattern = '[-+]';
|
||||||
|
$dateIntervalFormat = substr($dateIntervalFormat, 2);
|
||||||
|
break;
|
||||||
|
case '%r':
|
||||||
|
$signPattern = '-?';
|
||||||
|
$dateIntervalFormat = substr($dateIntervalFormat, 2);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
$valuePattern = '/^'.$signPattern.preg_replace('/%([yYmMdDhHiIsSwW])(\w)/', '(?P<$1>\d+)$2', $dateIntervalFormat).'$/';
|
||||||
if (!preg_match($valuePattern, $data)) {
|
if (!preg_match($valuePattern, $data)) {
|
||||||
throw new UnexpectedValueException(sprintf('Value "%s" contains intervals not accepted by format "%s".', $data, $dateIntervalFormat));
|
throw new UnexpectedValueException(sprintf('Value "%s" contains intervals not accepted by format "%s".', $data, $dateIntervalFormat));
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
if ('-' === $data[0]) {
|
||||||
|
$interval = new \DateInterval(substr($data, 1));
|
||||||
|
$interval->invert = 1;
|
||||||
|
|
||||||
|
return $interval;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ('+' === $data[0]) {
|
||||||
|
return new \DateInterval(substr($data, 1));
|
||||||
|
}
|
||||||
|
|
||||||
return new \DateInterval($data);
|
return new \DateInterval($data);
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
throw new UnexpectedValueException($e->getMessage(), $e->getCode(), $e);
|
throw new UnexpectedValueException($e->getMessage(), $e->getCode(), $e);
|
||||||
@ -98,6 +120,6 @@ class DateIntervalNormalizer implements NormalizerInterface, DenormalizerInterfa
|
|||||||
|
|
||||||
private function isISO8601($string)
|
private function isISO8601($string)
|
||||||
{
|
{
|
||||||
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);
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -29,6 +29,11 @@ class DateIntervalNormalizerTest extends TestCase
|
|||||||
['P%yY%mM%dDT%hH%iM', 'P10Y2M3DT16H5M', 'P10Y2M3DT16H5M'],
|
['P%yY%mM%dDT%hH%iM', 'P10Y2M3DT16H5M', 'P10Y2M3DT16H5M'],
|
||||||
['P%yY%mM%dDT%hH', 'P10Y2M3DT16H', 'P10Y2M3DT16H'],
|
['P%yY%mM%dDT%hH', 'P10Y2M3DT16H', 'P10Y2M3DT16H'],
|
||||||
['P%yY%mM%dD', 'P10Y2M3D', 'P10Y2M3DT0H'],
|
['P%yY%mM%dD', 'P10Y2M3D', 'P10Y2M3DT0H'],
|
||||||
|
['%RP%yY%mM%dD', '-P10Y2M3D', '-P10Y2M3DT0H'],
|
||||||
|
['%RP%yY%mM%dD', '+P10Y2M3D', '+P10Y2M3DT0H'],
|
||||||
|
['%RP%yY%mM%dD', '+P10Y2M3D', 'P10Y2M3DT0H'],
|
||||||
|
['%rP%yY%mM%dD', '-P10Y2M3D', '-P10Y2M3DT0H'],
|
||||||
|
['%rP%yY%mM%dD', 'P10Y2M3D', 'P10Y2M3DT0H'],
|
||||||
];
|
];
|
||||||
|
|
||||||
return $data;
|
return $data;
|
||||||
@ -50,7 +55,7 @@ class DateIntervalNormalizerTest extends TestCase
|
|||||||
*/
|
*/
|
||||||
public function testNormalizeUsingFormatPassedInContext($format, $output, $input)
|
public function testNormalizeUsingFormatPassedInContext($format, $output, $input)
|
||||||
{
|
{
|
||||||
$this->assertEquals($output, $this->normalizer->normalize(new \DateInterval($input), null, [DateIntervalNormalizer::FORMAT_KEY => $format]));
|
$this->assertEquals($output, $this->normalizer->normalize($this->getInterval($input), null, [DateIntervalNormalizer::FORMAT_KEY => $format]));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -58,7 +63,7 @@ class DateIntervalNormalizerTest extends TestCase
|
|||||||
*/
|
*/
|
||||||
public function testNormalizeUsingFormatPassedInConstructor($format, $output, $input)
|
public function testNormalizeUsingFormatPassedInConstructor($format, $output, $input)
|
||||||
{
|
{
|
||||||
$this->assertEquals($output, (new DateIntervalNormalizer($format))->normalize(new \DateInterval($input)));
|
$this->assertEquals($output, (new DateIntervalNormalizer($format))->normalize($this->getInterval($input)));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testNormalizeInvalidObjectThrowsException()
|
public function testNormalizeInvalidObjectThrowsException()
|
||||||
@ -84,7 +89,7 @@ class DateIntervalNormalizerTest extends TestCase
|
|||||||
*/
|
*/
|
||||||
public function testDenormalizeUsingFormatPassedInContext($format, $input, $output)
|
public function testDenormalizeUsingFormatPassedInContext($format, $input, $output)
|
||||||
{
|
{
|
||||||
$this->assertDateIntervalEquals(new \DateInterval($output), $this->normalizer->denormalize($input, \DateInterval::class, null, [DateIntervalNormalizer::FORMAT_KEY => $format]));
|
$this->assertDateIntervalEquals($this->getInterval($input), $this->normalizer->denormalize($input, \DateInterval::class, null, [DateIntervalNormalizer::FORMAT_KEY => $format]));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -92,7 +97,7 @@ class DateIntervalNormalizerTest extends TestCase
|
|||||||
*/
|
*/
|
||||||
public function testDenormalizeUsingFormatPassedInConstructor($format, $input, $output)
|
public function testDenormalizeUsingFormatPassedInConstructor($format, $input, $output)
|
||||||
{
|
{
|
||||||
$this->assertDateIntervalEquals(new \DateInterval($output), (new DateIntervalNormalizer($format))->denormalize($input, \DateInterval::class));
|
$this->assertDateIntervalEquals($this->getInterval($input), (new DateIntervalNormalizer($format))->denormalize($input, \DateInterval::class));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testDenormalizeExpectsString()
|
public function testDenormalizeExpectsString()
|
||||||
@ -124,4 +129,20 @@ class DateIntervalNormalizerTest extends TestCase
|
|||||||
{
|
{
|
||||||
$this->assertEquals($expected->format('%RP%yY%mM%dDT%hH%iM%sS'), $actual->format('%RP%yY%mM%dDT%hH%iM%sS'));
|
$this->assertEquals($expected->format('%RP%yY%mM%dDT%hH%iM%sS'), $actual->format('%RP%yY%mM%dDT%hH%iM%sS'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function getInterval($data)
|
||||||
|
{
|
||||||
|
if ('-' === $data[0]) {
|
||||||
|
$interval = new \DateInterval(substr($data, 1));
|
||||||
|
$interval->invert = 1;
|
||||||
|
|
||||||
|
return $interval;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ('+' === $data[0]) {
|
||||||
|
return new \DateInterval(substr($data, 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
return new \DateInterval($data);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user