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 fabf9ae

Browse filesBrowse files
committed
[Yaml] support to parse and dump DateTime objects
1 parent 1f80683 commit fabf9ae
Copy full SHA for fabf9ae

File tree

5 files changed

+95
-22
lines changed
Filter options

5 files changed

+95
-22
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
* Added support for customizing the YAML parser behavior through an optional bit field:
816

917
```php

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

Copy file name to clipboardExpand all lines: src/Symfony/Component/Yaml/Inline.php
+31-18Lines changed: 31 additions & 18 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
@@ -290,7 +293,7 @@ public static function parseScalar($scalar, $delimiters = null, $stringDelimiter
290293
}
291294

292295
if ($evaluate) {
293-
$output = self::evaluateScalar($output, $references);
296+
$output = self::evaluateScalar($output, $flags, $references);
294297
}
295298
}
296299

@@ -331,14 +334,15 @@ private static function parseQuotedScalar($scalar, &$i)
331334
* Parses a sequence to a YAML string.
332335
*
333336
* @param string $sequence
337+
* @param int $flags
334338
* @param int &$i
335339
* @param array $references
336340
*
337341
* @return string A YAML string
338342
*
339343
* @throws ParseException When malformed inline YAML string is parsed
340344
*/
341-
private static function parseSequence($sequence, &$i = 0, $references = array())
345+
private static function parseSequence($sequence, $flags, &$i = 0, $references = array())
342346
{
343347
$output = array();
344348
$len = strlen($sequence);
@@ -349,11 +353,11 @@ private static function parseSequence($sequence, &$i = 0, $references = array())
349353
switch ($sequence[$i]) {
350354
case '[':
351355
// nested sequence
352-
$output[] = self::parseSequence($sequence, $i, $references);
356+
$output[] = self::parseSequence($sequence, $flags, $i, $references);
353357
break;
354358
case '{':
355359
// nested mapping
356-
$output[] = self::parseMapping($sequence, $i, $references);
360+
$output[] = self::parseMapping($sequence, $flags, $i, $references);
357361
break;
358362
case ']':
359363
return $output;
@@ -362,14 +366,14 @@ private static function parseSequence($sequence, &$i = 0, $references = array())
362366
break;
363367
default:
364368
$isQuoted = in_array($sequence[$i], array('"', "'"));
365-
$value = self::parseScalar($sequence, array(',', ']'), array('"', "'"), $i, true, $references);
369+
$value = self::parseScalar($sequence, $flags, array(',', ']'), array('"', "'"), $i, true, $references);
366370

367371
// the value can be an array if a reference has been resolved to an array var
368372
if (!is_array($value) && !$isQuoted && false !== strpos($value, ': ')) {
369373
// embedded mapping?
370374
try {
371375
$pos = 0;
372-
$value = self::parseMapping('{'.$value.'}', $pos, $references);
376+
$value = self::parseMapping('{'.$value.'}', $flags, $pos, $references);
373377
} catch (\InvalidArgumentException $e) {
374378
// no, it's not
375379
}
@@ -390,14 +394,15 @@ private static function parseSequence($sequence, &$i = 0, $references = array())
390394
* Parses a mapping to a YAML string.
391395
*
392396
* @param string $mapping
397+
* @param int $flags
393398
* @param int &$i
394399
* @param array $references
395400
*
396401
* @return string A YAML string
397402
*
398403
* @throws ParseException When malformed inline YAML string is parsed
399404
*/
400-
private static function parseMapping($mapping, &$i = 0, $references = array())
405+
private static function parseMapping($mapping, $flags, &$i = 0, $references = array())
401406
{
402407
$output = array();
403408
$len = strlen($mapping);
@@ -419,7 +424,7 @@ private static function parseMapping($mapping, &$i = 0, $references = array())
419424
}
420425

421426
// key
422-
$key = self::parseScalar($mapping, array(':', ' '), array('"', "'"), $i, false);
427+
$key = self::parseScalar($mapping, $flags, array(':', ' '), array('"', "'"), $i, false);
423428

424429
// value
425430
$done = false;
@@ -428,7 +433,7 @@ private static function parseMapping($mapping, &$i = 0, $references = array())
428433
switch ($mapping[$i]) {
429434
case '[':
430435
// nested sequence
431-
$value = self::parseSequence($mapping, $i, $references);
436+
$value = self::parseSequence($mapping, $flags, $i, $references);
432437
// Spec: Keys MUST be unique; first one wins.
433438
// Parser cannot abort this mapping earlier, since lines
434439
// are processed sequentially.
@@ -439,7 +444,7 @@ private static function parseMapping($mapping, &$i = 0, $references = array())
439444
break;
440445
case '{':
441446
// nested mapping
442-
$value = self::parseMapping($mapping, $i, $references);
447+
$value = self::parseMapping($mapping, $flags, $i, $references);
443448
// Spec: Keys MUST be unique; first one wins.
444449
// Parser cannot abort this mapping earlier, since lines
445450
// are processed sequentially.
@@ -452,7 +457,7 @@ private static function parseMapping($mapping, &$i = 0, $references = array())
452457
case ' ':
453458
break;
454459
default:
455-
$value = self::parseScalar($mapping, array(',', '}'), array('"', "'"), $i, true, $references);
460+
$value = self::parseScalar($mapping, $flags, array(',', '}'), array('"', "'"), $i, true, $references);
456461
// Spec: Keys MUST be unique; first one wins.
457462
// Parser cannot abort this mapping earlier, since lines
458463
// are processed sequentially.
@@ -478,13 +483,14 @@ private static function parseMapping($mapping, &$i = 0, $references = array())
478483
* Evaluates scalars and replaces magic values.
479484
*
480485
* @param string $scalar
486+
* @param int $flags
481487
* @param array $references
482488
*
483489
* @return string A YAML string
484490
*
485491
* @throws ParseException when object parsing support was disabled and the parser detected a PHP object or when a reference could not be resolved
486492
*/
487-
private static function evaluateScalar($scalar, $references = array())
493+
private static function evaluateScalar($scalar, $flags, $references = array())
488494
{
489495
$scalar = trim($scalar);
490496
$scalarLower = strtolower($scalar);
@@ -523,7 +529,7 @@ private static function evaluateScalar($scalar, $references = array())
523529
case 0 === strpos($scalar, '!str'):
524530
return (string) substr($scalar, 5);
525531
case 0 === strpos($scalar, '! '):
526-
return (int) self::parseScalar(substr($scalar, 2));
532+
return (int) self::parseScalar(substr($scalar, 2), $flags);
527533
case 0 === strpos($scalar, '!php/object:'):
528534
if (self::$objectSupport) {
529535
return unserialize(substr($scalar, 12));
@@ -568,8 +574,15 @@ private static function evaluateScalar($scalar, $references = array())
568574
return log(0);
569575
case preg_match('/^(-|\+)?[0-9,]+(\.[0-9]+)?$/', $scalar):
570576
return (float) str_replace(',', '', $scalar);
577+
case preg_match(self::getTimestampRegex(), $scalar) && Yaml::PARSE_DATETIME & $flags:
578+
return new \DateTime($scalar,new \DateTimeZone('UTC'));
571579
case preg_match(self::getTimestampRegex(), $scalar):
572-
return strtotime($scalar);
580+
$timeZone = date_default_timezone_get();
581+
date_default_timezone_set('UTC');
582+
$time = strtotime($scalar);
583+
date_default_timezone_set($timeZone);
584+
585+
return $time;
573586
}
574587
default:
575588
return (string) $scalar;

‎src/Symfony/Component/Yaml/Tests/Fixtures/YtsSpecificationExamples.yml

Copy file name to clipboardExpand all lines: src/Symfony/Component/Yaml/Tests/Fixtures/YtsSpecificationExamples.yml
+2-2Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -754,7 +754,7 @@ yaml: |
754754
Billsmer @ 338-4338.
755755
php: |
756756
array(
757-
'invoice' => 34843, 'date' => mktime(0, 0, 0, 1, 23, 2001),
757+
'invoice' => 34843, 'date' => gmmktime(0, 0, 0, 1, 23, 2001),
758758
'bill-to' =>
759759
array( 'given' => 'Chris', 'family' => 'Dumars', 'address' => array( 'lines' => "458 Walkman Dr.\nSuite #292\n", 'city' => 'Royal Oak', 'state' => 'MI', 'postal' => 48046 ) )
760760
, 'ship-to' =>
@@ -879,7 +879,7 @@ yaml: |
879879
php: |
880880
array(
881881
'invoice' => 34843,
882-
'date' => mktime(0, 0, 0, 1, 23, 2001),
882+
'date' => gmmktime(0, 0, 0, 1, 23, 2001),
883883
'total' => 4443.52
884884
)
885885
---

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

Copy file name to clipboardExpand all lines: src/Symfony/Component/Yaml/Tests/InlineTest.php
+53-2Lines changed: 53 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -285,7 +285,7 @@ public function getTestsForParse()
285285
array("'on'", 'on'),
286286
array("'off'", 'off'),
287287

288-
array('2007-10-30', mktime(0, 0, 0, 10, 30, 2007)),
288+
array('2007-10-30', gmmktime(0, 0, 0, 10, 30, 2007)),
289289
array('2007-10-30T02:59:43Z', gmmktime(2, 59, 43, 10, 30, 2007)),
290290
array('2007-10-30 02:59:43 Z', gmmktime(2, 59, 43, 10, 30, 2007)),
291291
array('1960-10-30 02:59:43 Z', gmmktime(2, 59, 43, 10, 30, 1960)),
@@ -352,7 +352,7 @@ public function getTestsForParseWithMapObjects()
352352
array("'#cfcfcf'", '#cfcfcf'),
353353
array('::form_base.html.twig', '::form_base.html.twig'),
354354

355-
array('2007-10-30', mktime(0, 0, 0, 10, 30, 2007)),
355+
array('2007-10-30', gmmktime(0, 0, 0, 10, 30, 2007)),
356356
array('2007-10-30T02:59:43Z', gmmktime(2, 59, 43, 10, 30, 2007)),
357357
array('2007-10-30 02:59:43 Z', gmmktime(2, 59, 43, 10, 30, 2007)),
358358
array('1960-10-30 02:59:43 Z', gmmktime(2, 59, 43, 10, 30, 1960)),
@@ -460,4 +460,55 @@ public function getTestsForDump()
460460
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')),
461461
);
462462
}
463+
464+
/**
465+
* @dataProvider getTimestampTests
466+
*/
467+
public function testParseTimestampAsUnixTimestampByDefault($yaml, $year, $month, $day, $hour, $minute, $second)
468+
{
469+
$this->assertSame(gmmktime($hour, $minute, $second, $month, $day, $year), Inline::parse($yaml));
470+
}
471+
472+
/**
473+
* @dataProvider getTimestampTests
474+
*/
475+
public function testParseTimestampAsDateTimeObject($yaml, $year, $month, $day, $hour, $minute, $second)
476+
{
477+
$expected = new \DateTime('now', new \DateTimeZone('UTC'));
478+
$expected->setDate($year, $month, $day);
479+
$expected->setTime($hour, $minute, $second);
480+
481+
$this->assertEquals($expected, Inline::parse($yaml, Yaml::PARSE_DATETIME));
482+
}
483+
484+
public function getTimestampTests()
485+
{
486+
return array(
487+
'canonical' => array('2001-12-15T02:59:43.1Z', 2001, 12, 15, 2, 59, 43),
488+
'ISO-8601' => array('2001-12-15t21:59:43.10-05:00', 2001, 12, 16, 2, 59, 43),
489+
'spaced' => array('2001-12-15 21:59:43.10 -5', 2001, 12, 16, 2, 59, 43),
490+
'date' => array('2001-12-15', 2001, 12, 15, 0, 0, 0),
491+
);
492+
}
493+
494+
/**
495+
* @dataProvider getDateTimeDumpTests
496+
*/
497+
public function testDumpDateTime($dateTime, $expected)
498+
{
499+
$this->assertSame($expected, Inline::dump($dateTime));
500+
}
501+
502+
public function getDateTimeDumpTests()
503+
{
504+
$tests = array();
505+
506+
$dateTime = new \DateTime('2001-12-15 21:59:43', new \DateTimeZone('UTC'));
507+
$tests['date-time-utc'] = array($dateTime, '2001-12-15T21:59:43+00:00');
508+
509+
$dateTime = new \DateTimeImmutable('2001-07-15 21:59:43', new \DateTimeZone('Europe/Berlin'));
510+
$tests['immutable-date-time-europe-berlin'] = array($dateTime, '2001-07-15T21:59:43+02:00');
511+
512+
return $tests;
513+
}
463514
}

‎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.