8000 [Yaml] Allow milliseconds and microseconds in dates · symfony/symfony@ab65798 · GitHub
[go: up one dir, main page]

Skip to content

Commit ab65798

Browse files
committed
[Yaml] Allow milliseconds and microseconds in dates
1 parent a08a41c commit ab65798

File tree

5 files changed

+80
-10
lines changed

5 files changed

+80
-10
lines changed

CHANGELOG-6.2.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -331,4 +331,4 @@ To get the diff between two versions, go to https://github.com/symfony/symfony/c
331331
* feature #46430 [Routing] Add `Requirement::POSITIVE_INT` for common ids and pagination (HeahDude)
332332
* feature #46279 [DependencyInjection] Optimize autowiring logic by telling it about excluded symbols (nicolas-grekas)
333333
* feature #46452 [DependencyInjection] Add Hydrator::hydrate() and preserve PHP references when using it (nicolas-grekas)
334-
334+
* feature #48920 [Yaml] Allow milliseconds and microseconds in dates (dustinwilson)

src/Symfony/Component/Yaml/Inline.php

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,16 @@ public static function dump(mixed $value, int $flags = 0): string
110110

111111
return self::dumpNull($flags);
112112
case $value instanceof \DateTimeInterface:
113-
return $value->format('c');
113+
$length = \strlen(rtrim($value->format('u'), '0'));
114+
if (0 === $length) {
115+
$format = 'c';
116+
} elseif ($length < 4) {
117+
$format = 'Y-m-d\TH:i:s.vP';
118+
} else {
119+
$format = 'Y-m-d\TH:i:s.uP';
120+
}
121+
122+
return $value->format($format);
114123
case $value instanceof \UnitEnum:
115124
return sprintf('!php/const %s::%s', $value::class, $value->name);
116125
case \is_object($value):
@@ -712,15 +721,20 @@ private static function evaluateScalar(string $scalar, int $flags, array &$refer
712721
return $time;
713722
}
714723

715-
try {
716-
if (false !== $scalar = $time->getTimestamp()) {
717-
return $scalar;
724+
$length = \strlen(rtrim($time->format('u'), '0'));
725+
if (0 === $length) {
726+
try {
727+
if (false !== $scalar = $time->getTimestamp()) {
728+
return $scalar;
729+
}
730+
} catch (\ValueError) {
731+
// no-op
718732
}
719-
} catch (\ValueError) {
720-
// no-op
733+
734+
return (int) $time->format('U');
721735
}
722736

723-
return $time->format('U');
737+
return (float) $time->format('U.u');
724738
}
725739
}
726740

src/Symfony/Component/Yaml/Tests/DumperTest.php

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -922,6 +922,52 @@ public function testDumpIdeographicSpaces()
922922
], 2));
923923
}
924924

925+
/**
926+
* @dataProvider getDateTimeData
927+
*/
928+
public function testDumpDateTime(array $input, string $expected)
929+
{
930+
$this->assertSame($expected, rtrim($this->dumper->dump($input, 1)));
931+
}
932+
933+
public function getDateTimeData()
934+
{
935+
yield 'Date without subsecond precision' => [
936+
['date' => new \DateTimeImmutable('2023-01-24T01:02:03Z')],
937+
'date: 2023-01-24T01:02:03+00:00',
938+
];
939+
940+
yield 'Date with one digit for milliseconds' => [
941+
['date' => new \DateTimeImmutable('2023-01-24T01:02:03.4Z')],
942+
'date: 2023-01-24T01:02:03.400+00:00',
943+
];
944+
945+
yield 'Date with two digits for milliseconds' => [
946+
['date' => new \DateTimeImmutable('2023-01-24T01:02:03.45Z')],
947+
'date: 2023-01-24T01:02:03.450+00:00',
948+
];
949+
950+
yield 'Date with full milliseconds' => [
951+
['date' => new \DateTimeImmutable('2023-01-24T01:02:03.456Z')],
952+
'date: 2023-01-24T01:02:03.456+00:00',
953+
];
954+
955+
yield 'Date with four digits for microseconds' => [
956+
['date' => new \DateTimeImmutable('2023-01-24T01:02:03.4567Z')],
957+
'date: 2023-01-24T01:02:03.456700+00:00',
958+
];
959+
960+
yield 'Date with five digits for microseconds' => [
961+
['date' => new \DateTimeImmutable('2023-01-24T01:02:03.45678Z')],
962+
'date: 2023-01-24T01:02:03.456780+00:00',
963+
];
964+
965+
yield 'Date with full microseconds' => [
966+
['date' => new \DateTimeImmutable('2023-01-24T01:02:03.456789Z')],
967+
'date: 2023-01-24T01:02:03.456789+00:00',
968+
];
969+
}
970+
925971
private function assertSameData($expected, $actual)
926972
{
927973
$this->assertEquals($expected, $actual);

src/Symfony/Component/Yaml/Tests/InlineTest.php

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -563,9 +563,10 @@ public function getTestsForDump()
563563
/**
564564
* @dataProvider getTimestampTests
565565
*/
566-
public function testParseTimestampAsUnixTimestampByDefault(string $yaml, int $year, int $month, int $day, int $hour, int $minute, int $second)
566+
public function testParseTimestampAsUnixTimestampByDefault(string $yaml, int $year, int $month, int $day, int $hour, int $minute, int $second, int $microsecond)
567567
{
568-
$this->assertSame(gmmktime($hour, $minute, $second, $month, $day, $year), Inline::parse($yaml));
568+
$expectedDate = (new \DateTimeImmutable($yaml))->format('U');
569+
$this->assertSame(($microsecond) ? (float) "$expectedDate.$microsecond" : (int) $expectedDate, Inline::parse($yaml));
569570
}
570571

571572
/**

src/Symfony/Component/Yaml/Tests/ParserTest.php

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1541,6 +1541,15 @@ public function getInvalidBinaryData()
15411541
];
15421542
}
15431543

1544+
public function testParseDateWithSubseconds()
1545+
{
1546+
$yaml = <<<'EOT'
1547+
date: 2002-12-14T01:23:45.670000Z
1548+
EOT;
1549+
1550+
$this->assertSameData(['date' => 1039829025.67], $this->parser->parse($yaml));
1551+
}
1552+
15441553
public function testParseDateAsMappingValue()
15451554
{
15461555
$yaml = <<<'EOT'

0 commit comments

Comments
 (0)
0