php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Request #53831 DateInterval constructor does not handle valid ISO 8601 strings
Submitted: 2011-01-24 18:41 UTC Modified: -
Votes:39
Avg. Score:4.4 ± 0.9
Reproduced:39 of 39 (100.0%)
Same Version:11 (28.2%)
Same OS:8 (20.5%)
From: pallinger at dsd dot sztaki dot hu Assigned:
Status: Open Package: Date/time related
PHP Version: 5.3.5 OS: ubuntu linux 10.10
Private report: No CVE-ID: None
View Add Comment Developer Edit
Welcome! If you don't have a Git account, you can't do anything here.
You can add a comment by following this link or if you reported this bug, you can edit this bug over here.
(description)
Block user comment
Status: Assign to:
Package:
Bug Type:
Summary:
From: pallinger at dsd dot sztaki dot hu
New email:
PHP Version: OS:

 

 [2011-01-24 18:41 UTC] pallinger at dsd dot sztaki dot hu
Description:
------------
---
From manual page: http://www.php.net/dateinterval.construct
---
The documentation says that "Each duration period is represented by an integer value followed by a period designator.", however, the ISO 8601 allows non-integer values for the last number (http://en.wikipedia.org/wiki/ISO_8601#Durations).
This is quite important if I want to parse XML data which contains millisecond-precision durations, as the seconds will surely not be integers.

Test script:
---------------
<?php 
   var_dump(new DateInterval('PT1.1S'));
?>

Expected result:
----------------
Should print out a valid DateInterval object, eg.:
object(DateInterval)#1 (8) {
  ["y"]=>
  int(0)
  ["m"]=>
  int(0)
  ["d"]=>
  int(0)
  ["h"]=>
  int(0)
  ["i"]=>
  int(0)
  ["s"]=>
  float(1.1)
  ["invert"]=>
  int(0)
  ["days"]=>
  bool(false)
}
It could also include a millisecond/microsecond/nanosecond field to accomodate additional precision. However, if the durations that are stored are still integers, it would be difficult to handle durations like "P0.5Y".

Actual result:
--------------
PHP Fatal error:  Uncaught exception 'Exception' with message 'DateInterval::__construct(): Unknown or bad format (PT1.1S)' in -:1
Stack trace:
#0 -(1): DateInterval->__construct('PT1.1S')
#1 {main}
  thrown in - on line 1


Patches

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2011-10-12 16:09 UTC] dagguh at gmail dot com
http://en.wikipedia.org/wiki/Iso8601#Durations

This decimal fraction may be specified with either a comma or a full stop, as in 
"P0,5Y" or "P0.5Y".

Remember to accept both comma and a full stop.
 [2012-04-02 10:47 UTC] jdp2234 at hotmail dot com
http://joshp.me/dateinterval-milliseconds/
Quick class to get around it, while the bug still exists...
class DateIntervalFractions extends DateInterval {
	public $milliseconds;
	public function __construct($interval_spec) {
		$this->milliseconds = 0;
		$matches = array();
		preg_match_all("#([0-9]*[.,]?[0-9]*)
[S]#",$interval_spec,$matches);
		foreach ($matches[0] as $result)
		{
			$original = $result;
			list($seconds,$milliseconds) = 
explode(".",substr($result,0,-1));
			$this->milliseconds = $milliseconds / 
pow(10,strlen($milliseconds) - 3);

                        // Replace the milliseconds back to seconds,
                        // and let the original constructor do the rest.
			$interval_spec = str_replace($original,$seconds . 
"S",$interval_spec);
		}
		parent::__construct($interval_spec);
	}
}
 [2017-12-05 22:46 UTC] sloanlance+php dot net at gmail dot com
I'm surprised this bug has persisted since 2011-01-24.  This seems to have been implemented incorrectly from the beginning.  ISO 8601 has mentioned support for fractional parts since at least 2004.

That is, it supports a decimal fraction to the smallest time value in a representation.

For example, the following representations are valid ISO 8601 intervals, but will cause the DateInterval constructor to throw exceptions:

P0.5Y
P2.3D
P1DT1.5H
PT585.829S

I appreciate the attempted workaround by "jdp2234 at hotmail dot com", but it appears to only support milliseconds.  It doesn't seem to address fractions in other parts of interval representations.
 [2019-01-10 19:15 UTC] mdwyer at michaelmdwyer dot com
This appears to still be an issue with PHP 7.2, despite them adding a microseconds field to DateInterval.  My current workaround is:

        $fractional = new DateInterval('PT0S');
        $fractional->f = ".{$microseconds}";
        $fractional->invert = $seconds < 0;

        return (new DateTime("@{$seconds}"))->add($fractional);
 
PHP Copyright © 2001-2019 The PHP Group
All rights reserved.
Last updated: Wed Feb 20 18:01:27 2019 UTC