Skip to content

Commit 864837e

Browse files
committed
feature #49164 [Yaml] Feature #48920 Allow milliseconds and microseconds in dates (dustinwilson)
This PR was squashed before being merged into the 6.3 branch. Discussion ---------- [Yaml] Feature #48920 Allow milliseconds and microseconds in dates | Q | A | ------------- | --- | Branch? | 6.3 | Bug fix? | no | New feature? | yes | Deprecations? | no | Tickets | Feature #48920 | License | MIT | Doc PR | forthcoming Allows Yaml to parse dates with milliseconds or microseconds and to dump them as well. Commits ------- 8afb4c7702 [Yaml] Feature #48920 Allow milliseconds and microseconds in dates
2 parents f06e75f + eaa9afa commit 864837e

File tree

4 files changed

+79
-9
lines changed

4 files changed

+79
-9
lines changed

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

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);

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
/**

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)