Skip to content

Commit d45ef9a

Browse files
committed
[Serializer] Allow to cast certain DateTime formats to int/float
1 parent 0d9562f commit d45ef9a

File tree

4 files changed

+75
-2
lines changed

4 files changed

+75
-2
lines changed

src/Symfony/Component/Serializer/CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
CHANGELOG
22
=========
33

4+
7.1
5+
---
6+
7+
* Allow to cast certain DateTime formats to int/float
8+
49
7.0
510
---
611

src/Symfony/Component/Serializer/Context/Normalizer/DateTimeNormalizerContextBuilder.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,4 +61,9 @@ public function withTimezone(\DateTimeZone|string|null $timezone): static
6161

6262
return $this->with(DateTimeNormalizer::TIMEZONE_KEY, $timezone);
6363
}
64+
65+
public function withTimestampCast(bool $cast): static
66+
{
67+
return $this->with(DateTimeNormalizer::TIMESTAMP_CAST_KEY, $cast);
68+
}
6469
}

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

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,12 @@ final class DateTimeNormalizer implements NormalizerInterface, DenormalizerInter
2525
{
2626
public const FORMAT_KEY = 'datetime_format';
2727
public const TIMEZONE_KEY = 'datetime_timezone';
28+
public const TIMESTAMP_CAST_KEY = 'datetime_timestamp_cast';
2829

2930
private array $defaultContext = [
3031
self::FORMAT_KEY => \DateTimeInterface::RFC3339,
3132
self::TIMEZONE_KEY => null,
33+
self::TIMESTAMP_CAST_KEY => false,
3234
];
3335

3436
private const SUPPORTED_TYPES = [
@@ -59,7 +61,7 @@ public function getSupportedTypes(?string $format): array
5961
/**
6062
* @throws InvalidArgumentException
6163
*/
62-
public function normalize(mixed $object, string $format = null, array $context = []): string
64+
public function normalize(mixed $object, string $format = null, array $context = []): int|float|string
6365
{
6466
if (!$object instanceof \DateTimeInterface) {
6567
throw new InvalidArgumentException('The object must implement the "\DateTimeInterface".');
@@ -73,7 +75,16 @@ public function normalize(mixed $object, string $format = null, array $context =
7375
$object = $object->setTimezone($timezone);
7476
}
7577

76-
return $object->format($dateTimeFormat);
78+
return match ($context[self::TIMESTAMP_CAST_KEY] ?? $this->defaultContext[self::TIMESTAMP_CAST_KEY]) {
79+
true => match ($dateTimeFormat) {
80+
'U' => $object->getTimestamp(),
81+
'U.u' => (float) $object->format('U.u'),
82+
'Uv' => (int) $object->format('Uv'),
83+
'Uu' => (int) $object->format('Uu'),
84+
default => $object->format($dateTimeFormat),
85+
},
86+
default => $object->format($dateTimeFormat),
87+
};
7788
}
7889

7990
public function supportsNormalization(mixed $data, string $format = null, array $context = []): bool

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

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
use Symfony\Component\Serializer\Exception\InvalidArgumentException;
1616
use Symfony\Component\Serializer\Exception\UnexpectedValueException;
1717
use Symfony\Component\Serializer\Normalizer\DateTimeNormalizer;
18+
use Symfony\Component\Validator\Constraints\DateTime;
1819

1920
/**
2021
* @author Kévin Dunglas <dunglas@gmail.com>
@@ -154,6 +155,57 @@ public static function normalizeUsingTimeZonePassedInContextAndExpectedFormatWit
154155
];
155156
}
156157

158+
/**
159+
* @dataProvider provideNormalizeUsingTimestampCastCases
160+
*/
161+
public function testNormalizeUsingTimestampCast(\DateTimeInterface $date, string $format, int|float $expectedResult)
162+
{
163+
self::assertSame($expectedResult, $this->normalizer->normalize($date, null, [
164+
DateTimeNormalizer::TIMESTAMP_CAST_KEY => true,
165+
DateTimeNormalizer::FORMAT_KEY => $format,
166+
]));
167+
}
168+
169+
/**
170+
* @dataProvider provideNormalizeUsingTimestampCastCases
171+
*/
172+
public function testNormalizeUsingTimestampCastFromDefaultContext(\DateTimeInterface $date, string $format, int|float $expectedResult)
173+
{
174+
$normalizer = new DateTimeNormalizer([
175+
DateTimeNormalizer::TIMESTAMP_CAST_KEY => true,
176+
DateTimeNormalizer::FORMAT_KEY => $format,
177+
]);
178+
179+
self::assertSame($expectedResult, $normalizer->normalize($date));
180+
}
181+
182+
public static function provideNormalizeUsingTimestampCastCases()
183+
{
184+
yield [
185+
new \DateTimeImmutable('2016-01-01T00:00:00+00:00'),
186+
'U',
187+
1451606400,
188+
];
189+
190+
yield [
191+
new \DateTimeImmutable('2016-01-01T00:00:00.123456+00:00'),
192+
'U.u',
193+
1451606400.123456,
194+
];
195+
196+
yield [
197+
new \DateTimeImmutable('2016-01-01T00:00:00.123456+00:00'),
198+
'Uv',
199+
1451606400123,
200+
];
201+
202+
yield [
203+
new \DateTimeImmutable('2016-01-01T00:00:00.123456+00:00'),
204+
'Uu',
205+
1451606400123456,
206+
];
207+
}
208+
157209
public function testNormalizeInvalidObjectThrowsException()
158210
{
159211
$this->expectException(InvalidArgumentException::class);

0 commit comments

Comments
 (0)