Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 7e1c6c4

Browse filesBrowse files
committed
[Yaml] support to parse and dump DateTime objects
1 parent 3e9c268 commit 7e1c6c4
Copy full SHA for 7e1c6c4

File tree

4 files changed

+88
-18
lines changed
Filter options

4 files changed

+88
-18
lines changed

‎src/Symfony/Component/Yaml/CHANGELOG.md

Copy file name to clipboardExpand all lines: src/Symfony/Component/Yaml/CHANGELOG.md
+8Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,14 @@ CHANGELOG
44
3.1.0
55
-----
66

7+
* Added support for parsing timestamps as `\DateTime` objects:
8+
9+
```php
10+
Yaml::parse('2001-12-15 21:59:43.10 -5', Yaml::PARSE_DATETIME);
11+
```
12+
13+
* `\DateTime` and `\DateTimeImmutable` objects are dumped as YAML timestamps.
14+
715
* Deprecated usage of `%` at the beginning of an unquoted string.
816

917
* Added support for customizing the YAML parser behavior through an optional bit field:

‎src/Symfony/Component/Yaml/Inline.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Yaml/Inline.php
+27-17Lines changed: 27 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -92,15 +92,15 @@ public static function parse($value, $flags = 0, $references = array())
9292
$i = 0;
9393
switch ($value[0]) {
9494
case '[':
95-
$result = self::parseSequence($value, $i, $references);
95+
$result = self::parseSequence($value, $flags, $i, $references);
9696
++$i;
9797
break;
9898
case '{':
99-
$result = self::parseMapping($value, $i, $references);
99+
$result = self::parseMapping($value, $flags, $i, $references);
100100
++$i;
101101
break;
102102
default:
103-
$result = self::parseScalar($value, null, array('"', "'"), $i, true, $references);
103+
$result = self::parseScalar($value, $flags, null, array('"', "'"), $i, true, $references);
104104
}
105105

106106
// some comments are allowed at the end
@@ -152,6 +152,8 @@ public static function dump($value, $flags = 0)
152152
}
153153

154154
return 'null';
155+
case $value instanceof \DateTimeInterface:
156+
return $value->format('c');
155157
case is_object($value):
156158
if (Yaml::DUMP_OBJECT & $flags) {
157159
return '!php/object:'.serialize($value);
@@ -243,6 +245,7 @@ private static function dumpArray($value, $flags)
243245
* Parses a scalar to a YAML string.
244246
*
245247
* @param string $scalar
248+
* @param int $flags
246249
* @param string $delimiters
247250
* @param array $stringDelimiters
248251
* @param int &$i
@@ -255,7 +258,7 @@ private static function dumpArray($value, $flags)
255258
*
256259
* @internal
257260
*/
258-
public static function parseScalar($scalar, $delimiters = null, $stringDelimiters = array('"', "'"), &$i = 0, $evaluate = true, $references = array())
261+
public static function parseScalar($scalar, $flags = 0, $delimiters = null, $stringDelimiters = array('"', "'"), &$i = 0, $evaluate = true, $references = array())
259262
{
260263
if (in_array($scalar[$i], $stringDelimiters)) {
261264
// quoted scalar
@@ -294,7 +297,7 @@ public static function parseScalar($scalar, $delimiters = null, $stringDelimiter
294297
}
295298

296299
if ($evaluate) {
297-
$output = self::evaluateScalar($output, $references);
300+
$output = self::evaluateScalar($output, $flags, $references);
298301
}
299302
}
300303

@@ -335,14 +338,15 @@ private static function parseQuotedScalar($scalar, &$i)
335338
* Parses a sequence to a YAML string.
336339
*
337340
* @param string $sequence
341+
* @param int $flags
338342
* @param int &$i
339343
* @param array $references
340344
*
341345
* @return string A YAML string
342346
*
343347
* @throws ParseException When malformed inline YAML string is parsed
344348
*/
345-
private static function parseSequence($sequence, &$i = 0, $references = array())
349+
private static function parseSequence($sequence, $flags, &$i = 0, $references = array())
346350
{
347351
$output = array();
348352
$len = strlen($sequence);
@@ -353,11 +357,11 @@ private static function parseSequence($sequence, &$i = 0, $references = array())
353357
switch ($sequence[$i]) {
354358
case '[':
355359
// nested sequence
356-
$output[] = self::parseSequence($sequence, $i, $references);
360+
$output[] = self::parseSequence($sequence, $flags, $i, $references);
357361
break;
358362
case '{':
359363
// nested mapping
360-
$output[] = self::parseMapping($sequence, $i, $references);
364+
$output[] = self::parseMapping($sequence, $flags, $i, $references);
361365
break;
362366
case ']':
363367
return $output;
@@ -366,14 +370,14 @@ private static function parseSequence($sequence, &$i = 0, $references = array())
366370
break;
367371
default:
368372
$isQuoted = in_array($sequence[$i], array('"', "'"));
369-
$value = self::parseScalar($sequence, array(',', ']'), array('"', "'"), $i, true, $references);
373+
$value = self::parseScalar($sequence, $flags, array(',', ']'), array('"', "'"), $i, true, $references);
370374

371375
// the value can be an array if a reference has been resolved to an array var
372376
if (!is_array($value) && !$isQuoted && false !== strpos($value, ': ')) {
373377
// embedded mapping?
374378
try {
375379
$pos = 0;
376-
$value = self::parseMapping('{'.$value.'}', $pos, $references);
380+
$value = self::parseMapping('{'.$value.'}', $flags, $pos, $references);
377381
} catch (\InvalidArgumentException $e) {
378382
// no, it's not
379383
}
@@ -394,14 +398,15 @@ private static function parseSequence($sequence, &$i = 0, $references = array())
394398
* Parses a mapping to a YAML string.
395399
*
396400
* @param string $mapping
401+
* @param int $flags
397402
* @param int &$i
398403
* @param array $references
399404
*
400405
* @return string A YAML string
401406
*
402407
* @throws ParseException When malformed inline YAML string is parsed
403408
*/
404-
private static function parseMapping($mapping, &$i = 0, $references = array())
409+
private static function parseMapping($mapping, $flags, &$i = 0, $references = array())
405410
{
406411
$output = array();
407412
$len = strlen($mapping);
@@ -423,7 +428,7 @@ private static function parseMapping($mapping, &$i = 0, $references = array())
423428
}
424429

425430
// key
426-
$key = self::parseScalar($mapping, array(':', ' '), array('"', "'"), $i, false);
431+
$key = self::parseScalar($mapping, $flags, array(':', ' '), array('"', "'"), $i, false);
427432

428433
// value
429434
$done = false;
@@ -432,7 +437,7 @@ private static function parseMapping($mapping, &$i = 0, $references = array())
432437
switch ($mapping[$i]) {
433438
case '[':
434439
// nested sequence
435-
$value = self::parseSequence($mapping, $i, $references);
440+
$value = self::parseSequence($mapping, $flags, $i, $references);
436441
// Spec: Keys MUST be unique; first one wins.
437442
// Parser cannot abort this mapping earlier, since lines
438443
// are processed sequentially.
@@ -443,7 +448,7 @@ private static function parseMapping($mapping, &$i = 0, $references = array())
443448
break;
444449
case '{':
445450
// nested mapping
446-
$value = self::parseMapping($mapping, $i, $references);
451+
$value = self::parseMapping($mapping, $flags, $i, $references);
447452
// Spec: Keys MUST be unique; first one wins.
448453
// Parser cannot abort this mapping earlier, since lines
449454
// are processed sequentially.
@@ -456,7 +461,7 @@ private static function parseMapping($mapping, &$i = 0, $references = array())
456461
case ' ':
457462
break;
458463
default:
459-
$value = self::parseScalar($mapping, array(',', '}'), array('"', "'"), $i, true, $references);
464+
$value = self::parseScalar($mapping, $flags, array(',', '}'), array('"', "'"), $i, true, $references);
460465
// Spec: Keys MUST be unique; first one wins.
461466
// Parser cannot abort this mapping earlier, since lines
462467
// are processed sequentially.
@@ -482,13 +487,14 @@ private static function parseMapping($mapping, &$i = 0, $references = array())
482487
* Evaluates scalars and replaces magic values.
483488
*
484489
* @param string $scalar
490+
* @param int $flags
485491
* @param array $references
486492
*
487493
* @return string A YAML string
488494
*
489495
* @throws ParseException when object parsing support was disabled and the parser detected a PHP object or when a reference could not be resolved
490496
*/
491-
private static function evaluateScalar($scalar, $references = array())
497+
private static function evaluateScalar($scalar, $flags, $references = array())
492498
{
493499
$scalar = trim($scalar);
494500
$scalarLower = strtolower($scalar);
@@ -527,7 +533,7 @@ private static function evaluateScalar($scalar, $references = array())
527533
case 0 === strpos($scalar, '!str'):
528534
return (string) substr($scalar, 5);
529535
case 0 === strpos($scalar, '! '):
530-
return (int) self::parseScalar(substr($scalar, 2));
536+
return (int) self::parseScalar(substr($scalar, 2), $flags);
531537
case 0 === strpos($scalar, '!php/object:'):
532538
if (self::$objectSupport) {
533539
return unserialize(substr($scalar, 12));
@@ -573,6 +579,10 @@ private static function evaluateScalar($scalar, $references = array())
573579
case preg_match('/^(-|\+)?[0-9,]+(\.[0-9]+)?$/', $scalar):
574580
return (float) str_replace(',', '', $scalar);
575581
case preg_match(self::getTimestampRegex(), $scalar):
582+
if (Yaml::PARSE_DATETIME & $flags) {
583+
return new \DateTime($scalar,new \DateTimeZone('UTC'));
584+
}
585+
576586
$timeZone = date_default_timezone_get();
577587
date_default_timezone_set('UTC');
578588
$time = strtotime($scalar);

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

Copy file name to clipboardExpand all lines: src/Symfony/Component/Yaml/Tests/InlineTest.php
+52-1Lines changed: 52 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -373,7 +373,7 @@ public function getTestsForParseWithMapObjects()
373373
array("'#cfcfcf'", '#cfcfcf'),
374374
array('::form_base.html.twig', '::form_base.html.twig'),
375375

376-
array('2007-10-30', mktime(0, 0, 0, 10, 30, 2007)),
376+
array('2007-10-30', gmmktime(0, 0, 0, 10, 30, 2007)),
377377
array('2007-10-30T02:59:43Z', gmmktime(2, 59, 43, 10, 30, 2007)),
378378
array('2007-10-30 02:59:43 Z', gmmktime(2, 59, 43, 10, 30, 2007)),
379379
array('1960-10-30 02:59:43 Z', gmmktime(2, 59, 43, 10, 30, 1960)),
@@ -481,4 +481,55 @@ public function getTestsForDump()
481481
array('[foo, \'@foo.baz\', { \'%foo%\': \'foo is %foo%\', bar: \'%foo%\' }, true, \'@service_container\']', array('foo', '@foo.baz', array('%foo%' => 'foo is %foo%', 'bar' => '%foo%'), true, '@service_container')),
482482
);
483483
}
484+
485+
/**
486+
* @dataProvider getTimestampTests
487+
*/
488+
public function testParseTimestampAsUnixTimestampByDefault($yaml, $year, $month, $day, $hour, $minute, $second)
489+
{
490+
$this->assertSame(gmmktime($hour, $minute, $second, $month, $day, $year), Inline::parse($yaml));
491+
}
492+
493+
/**
494+
* @dataProvider getTimestampTests
495+
*/
496+
public function testParseTimestampAsDateTimeObject($yaml, $year, $month, $day, $hour, $minute, $second)
497+
{
498+
$expected = new \DateTime('now', new \DateTimeZone('UTC'));
499+
$expected->setDate($year, $month, $day);
500+
$expected->setTime($hour, $minute, $second);
501+
502+
$this->assertEquals($expected, Inline::parse($yaml, Yaml::PARSE_DATETIME));
503+
}
504+
505+
public function getTimestampTests()
506+
{
507+
return array(
508+
'canonical' => array('2001-12-15T02:59:43.1Z', 2001, 12, 15, 2, 59, 43),
509+
'ISO-8601' => array('2001-12-15t21:59:43.10-05:00', 2001, 12, 16, 2, 59, 43),
510+
'spaced' => array('2001-12-15 21:59:43.10 -5', 2001, 12, 16, 2, 59, 43),
511+
'date' => array('2001-12-15', 2001, 12, 15, 0, 0, 0),
512+
);
513+
}
514+
515+
/**
516+
* @dataProvider getDateTimeDumpTests
517+
*/
518+
public function testDumpDateTime($dateTime, $expected)
519+
{
520+
$this->assertSame($expected, Inline::dump($dateTime));
521+
}
522+
523+
public function getDateTimeDumpTests()
524+
{
525+
$tests = array();
526+
527+
$dateTime = new \DateTime('2001-12-15 21:59:43', new \DateTimeZone('UTC'));
528+
$tests['date-time-utc'] = array($dateTime, '2001-12-15T21:59:43+00:00');
529+
530+
$dateTime = new \DateTimeImmutable('2001-07-15 21:59:43', new \DateTimeZone('Europe/Berlin'));
531+
$tests['immutable-date-time-europe-berlin'] = array($dateTime, '2001-07-15T21:59:43+02:00');
532+
533+
return $tests;
534+
}
484535
}

‎src/Symfony/Component/Yaml/Yaml.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Yaml/Yaml.php
+1Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ class Yaml
2525
const PARSE_OBJECT = 4;
2626
const PARSE_OBJECT_FOR_MAP = 8;
2727
const DUMP_EXCEPTION_ON_INVALID_TYPE = 16;
28+
const PARSE_DATETIME = 32;
2829

2930
/**
3031
* Parses YAML into a PHP value.

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.