Req #53831 [Com]: DateInterval constructor does not handle valid ISO 8601 strings
| From: | mdwyer at michaelmdwyer dot com | Date: | Thu, 10 Jan 2019 19:15:05 +0000 |
| Subject: | Req #53831 [Com]: DateInterval constructor does not handle valid ISO 8601 strings | ||
| References: | 1 | Groups: | php.bugs |
| Request: | Send a blank email to php-bugs+get-218888@lists.php.net to get a copy of this message | ||
Edit report at https://bugs.php.net/bug.php?id=53831&edit=1
ID: 53831
Comment by: mdwyer at michaelmdwyer dot com
Reported by: pallinger at dsd dot sztaki dot hu
Summary: DateInterval constructor does not handle valid ISO
8601 strings
Status: Open
Type: Feature/Change Request
Package: Date/time related
Operating System: ubuntu linux 10.10
PHP Version: 5.3.5
Block user comment: N
Private report: N
New Comment:
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);
Previous Comments:
------------------------------------------------------------------------
[2017-12-05 22:46:04] 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.
------------------------------------------------------------------------
[2012-04-02 10:47:20] 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);
}
}
------------------------------------------------------------------------
[2011-10-12 16:09:31] 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.
------------------------------------------------------------------------
[2011-01-24 18:41:19] 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
------------------------------------------------------------------------
--
Edit this bug report at https://bugs.php.net/bug.php?id=53831&edit=1