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:27
Avg. Score:4.4 ± 0.8
Reproduced:27 of 27 (100.0%)
Same Version:8 (29.6%)
Same OS:4 (14.8%)
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
Have you experienced this issue?
Rate the importance of this bug to you:

 [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.
 
PHP Copyright © 2001-2017 The PHP Group
All rights reserved.
Last updated: Sun Nov 19 01:31:42 2017 UTC