Browse Source

DateTimeHelper::parse(): support iso durations in format PnYnMnDTnHnMnS and PnW

Fabian Peter Hammerle 7 years ago
parent
commit
b673e29107
2 changed files with 55 additions and 33 deletions
  1. 40 33
      DateTimeHelper.php
  2. 15 0
      tests/DateTimeHelperTest.php

+ 40 - 33
DateTimeHelper.php

@@ -34,40 +34,42 @@ class DateTimeHelper
     {
         if($text === null) {
             return null;
-        } else {
-            if(preg_match(
-                    '/^(?P<y>\d{4})-(?P<m>\d{2})-(?P<d>\d{2})'
-                        .'([ T](?P<h>\d{2}):(?P<i>\d{2})(:(?P<s>\d{2}))?)?'
-                        . '(' . self::_timezone_iso_pattern . ')?$/',
-                    $text,
-                    $attr
-                    )) {
-                $start = new \DateTime($text);
-                if(!empty($attr['s'])) {
-                    $interval = new \DateInterval('PT1S');
-                } elseif(!empty($attr['i'])) {
-                    $interval = new \DateInterval('PT1M');
-                } else {
-                    $interval = new \DateInterval('P1D');
-                }
-                return new \DatePeriod($start, $interval, 0);
-            } elseif(preg_match('/^\d{4}-(?P<m>\d{2})(( (?=-)| ?(?!-))' . self::_timezone_iso_pattern . ')?$/', $text, $attr)) {
-                return new \DatePeriod(
-                    new \DateTime($text),
-                    new \DateInterval('P1M'),
-                    0
-                    );
-            } elseif(preg_match('/^(?P<y>\d{4})( ?' . self::_timezone_iso_pattern . ')?$/', $text, $attr)) {
-                return new \DatePeriod(
-                    new \DateTime(sprintf(
-                        '%s-01-01 %s',
-                        $attr['y'],
-                        isset($attr['tz']) ? $attr['tz'] : ''
-                        )),
-                    new \DateInterval('P1Y'),
-                    0
-                    );
+        } elseif(preg_match(
+                '/^(?P<y>\d{4})-(?P<m>\d{2})-(?P<d>\d{2})'
+                    .'([ T](?P<h>\d{2}):(?P<i>\d{2})(:(?P<s>\d{2}))?)?'
+                    . '(' . self::_timezone_iso_pattern . ')?$/',
+                $text,
+                $attr
+                )) {
+            $start = new \DateTime($text);
+            if(!empty($attr['s'])) {
+                $interval = new \DateInterval('PT1S');
+            } elseif(!empty($attr['i'])) {
+                $interval = new \DateInterval('PT1M');
             } else {
+                $interval = new \DateInterval('P1D');
+            }
+            return new \DatePeriod($start, $interval, 0);
+        } elseif(preg_match('/^\d{4}-(?P<m>\d{2})(( (?=-)| ?(?!-))' . self::_timezone_iso_pattern . ')?$/', $text, $attr)) {
+            return new \DatePeriod(
+                new \DateTime($text),
+                new \DateInterval('P1M'),
+                0
+                );
+        } elseif(preg_match('/^(?P<y>\d{4})( ?' . self::_timezone_iso_pattern . ')?$/', $text, $attr)) {
+            return new \DatePeriod(
+                new \DateTime(sprintf(
+                    '%s-01-01 %s',
+                    $attr['y'],
+                    isset($attr['tz']) ? $attr['tz'] : ''
+                    )),
+                new \DateInterval('P1Y'),
+                0
+                );
+        } else {
+            try {
+                return new \DateInterval($text);
+            } catch(\Exception $ex) {
                 throw new \InvalidArgumentException(
                     sprintf("could not parse string '%s'", $text)
                     );
@@ -82,6 +84,11 @@ class DateTimeHelper
     public static function parseGetStart($text)
     {
         $period = self::parse($text);
+        if($period instanceof \DateInterval) {
+            throw new \InvalidArgumentException(
+                sprintf("'%s' defines a duration and does not provide any start date", $text)
+            );
+        }
         if($period) {
             return $period->start;
         } else {

+ 15 - 0
tests/DateTimeHelperTest.php

@@ -149,6 +149,18 @@ class DateTimeHelperTest extends \PHPUnit_Framework_TestCase
             ['2016-01-02T15:52:13+00:00', 'Europe/Vienna', new DP(new DT('2016-01-02T15:52:13Z'),      new DI('PT1S'), 0)],
             ['2016-01-02T15:52:13+02:00', 'US/Pacific',    new DP(new DT('2016-01-02T15:52:13+02:00'), new DI('PT1S'), 0)],
             ['2016-01-02T15:52:13-08:00', 'UTC',           new DP(new DT('2016-01-02T15:52:13-08:00'), new DI('PT1S'), 0)],
+            // durations PnYnMnDTnHnMnS
+            ['P1Y', 'UTC', new DI('P1Y')],
+            ['P3M', 'UTC', new DI('P3M')],
+            ['P5D', 'UTC', new DI('P5D')],
+            ['PT9H', 'UTC', new DI('PT9H')],
+            ['PT7M', 'US/Pacific', new DI('PT7M')],
+            ['PT6S', 'UTC', new DI('PT6S')],
+            ['P1Y3M5D', 'UTC', new DI('P1Y3M5D')],
+            ['PT9H7M6S', 'Europe/Vienna', new DI('PT9H7M6S')],
+            ['P1Y3M5DT9H7M6S', 'UTC', new DI('P1Y3M5DT9H7M6S')],
+            // durations PnW
+            ['P4W', 'UTC', new DI('P4W')],
             ];
     }
 
@@ -169,6 +181,8 @@ class DateTimeHelperTest extends \PHPUnit_Framework_TestCase
             ['2016--12'],
             ['2016-01-08:00'],
             ['2016-10-12 08:20#01'],
+            ['P'],
+            ['PT1'],
             [1],
             [false],
             ];
@@ -253,6 +267,7 @@ class DateTimeHelperTest extends \PHPUnit_Framework_TestCase
             ['2016--12'],
             ['2016-01-08:00'],
             ['2016-10-12 08:20#01'],
+            ['P1Y'],
             [1],
             [false],
             ];