php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #78590 DatePeriod 0 Recurrences Throws Exception since 7.2.19
Submitted: 2019-09-23 15:35 UTC Modified: 2019-09-24 10:57 UTC
From: will dot baumbach at iselinc dot com Assigned:
Status: Open Package: Date/time related
PHP Version: 7.2.22 OS: Linux
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: will dot baumbach at iselinc dot com
New email:
PHP Version: OS:

 

 [2019-09-23 15:35 UTC] will dot baumbach at iselinc dot com
Description:
------------
---
From manual page: https://php.net/dateperiod.construct
---

As of 7.2.19+, 7.3.6+ and 7.4.0+ the DatePeriod constructor recurrences argument, no longer accepts 0. Instead an exception is thrown.

This was an undocumented change in the 7.2.19 change log and on the DatePeriod documentation page.

Fatal error: Uncaught Exception: DatePeriod::__construct(): The recurrence count '0' is invalid. Needs to be > 0 in /in/vjVTF:6
Stack trace:
#0 /in/vjVTF(6): DatePeriod->__construct(Object(DateTimeImmutable), Object(DateInterval), 0)



Test script:
---------------
new \DatePeriod(new \DateTimeImmutable(), new \DateInterval('P1D'), 0);


https://3v4l.org/vjVTF




Patches

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2019-09-23 15:44 UTC] requinix@php.net
-Summary: DatePeriod 0 Recurrences Throws Exception +Summary: DatePeriod 0 Recurrences Throws Exception since 7.2.19 -Status: Open +Status: Verified
 [2019-09-23 15:44 UTC] requinix@php.net
See bug #77909

https://github.com/php/php-src/commit/7b1a4e24008f34a76c343ece735953ad5124e09f
Looks like the commit put the NEWS entry in the wrong section. Could explain why it's missing from the docs.

I'm leaving this as a regular non-doc bug because NEWS should probably be fixed.
 [2019-09-23 16:35 UTC] will dot baumbach at iselinc dot com
Shouldn't the update be reverted from a patch version to a minor version update. (affecting only 7.4+)? Since this is backward incompatible update, that changes the functional behavior of DatePeriod from PHP 5.3 to 7.2.18

https://semver.org/

While updating the documentation is needed, the change will break current applications that accept a 0+ argument, forcing a refactor of the code to address the exception.

It should however throw an Exception if < 0 as opposed to < 1, since 0 is an acceptable range to repeat a date period, where a negative or past date is not.

For example https://3v4l.org/ReWbN

$start = new DateTimeImmutable('2012-07-01');
$interval = new DateInterval('P1D');

$periodWithRecurrences = new \DatePeriod($start, $interval, $start->add($interval));
foreach($periodWithRecurrences as $date) {
    echo $date->format('Y-m-d') . \PHP_EOL;
}

echo \PHP_EOL;

$periodWithRecurrences = new DatePeriod($start, $interval, 0);
foreach($periodWithRecurrences as $date) {
    echo $date->format('Y-m-d') . \PHP_EOL;
}


Result 

2012-07-01

2012-07-01
 [2019-09-23 17:04 UTC] requinix@php.net
> Shouldn't the update be reverted from a patch version to a minor version update. (affecting only 7.4+)? Since this
> is backward incompatible update, that changes the functional behavior of DatePeriod from PHP 5.3 to 7.2.18
If you think that PHP should change its bug-fixing process so that all fixes resulting in a behavioral change must be postponed for the next series then you should bring it up on the internals mailing list. Until then, a bug fix is a bug fix.

> since 0 is an acceptable range to repeat a date period
0 means no repeating at all. If there's no repeating then there is no date range.

The current stance is that no recurrences is not permitted. Are you requesting that no recurrences be supported?
 [2019-09-23 20:22 UTC] will dot baumbach at iselinc dot com
>If you think that PHP should change its bug-fixing process so that all fixes resulting in a behavioral change must be postponed for the next series then you should bring it up on the internals mailing list. Until then, a bug fix is a bug fix.

This wasn't just a bug-fix, this is a backward incompatible change/BC Break as was stated in the pull request, as it breaks the API.

A similar change for count($string) emitting a warning for an invalid argument, was held off for a minor version where others suggested a major version.  https://github.com/php/php-src/pull/1672

So behavioral changes causing BC breaks is not something that appears to need to be addressed.

>0 means no repeating at all. If there's no repeating then there is no date range.

Period versus Range and Recurrence versus Occurrence.
For example a calendar event that repeats zero times.
The date period would reoccur 0 (zero) times, producing a date range with a single occurrence.

The old functionality would have produced a single date for the calendar event period as I demonstrated.

return new DatePeriod($calendarDate, $repeatInterval, $repeats);

Instead repeats now has to be validated to return an Iterable or change the repeats to a DateTimeInterface instead of an integer.

if ($repeats < 1) {
   return [$calendarDate];

   //or
   $endDate = clone $calendarDate;
   
   return new \DatePeriod($calendarDate, $repeatInterval, $endDate->add($repeatInterval));
}


>The current stance is that no recurrences is not permitted. Are you requesting that no recurrences be supported?

The ISO 8601 standard permits a repetition of 0 or more, 1 or more or n times.

https://web.archive.org/web/20171020084445/https://www.loc.gov/standards/datetime/ISO_DIS%208601-1.pdf
https://web.archive.org/web/20171020085148/https://www.loc.gov/standards/datetime/ISO_DIS%208601-2.pdf


"
Repetition (0 or more): {...}
Repetition (1 or more): {...}-
Repetition (n times): n * ...
"


If PHP is adhering to the ISO standards, then a repetition of 0 or more should be supported.

It appears the bug was with either the ISO 8601 repeating interval specification parsing not accepting zero recurrences or the new DatePeriod::getRecurrences() feature in 7.2.17 returning NULL instead of 0. https://3v4l.org/E8MT8
 [2019-09-23 20:28 UTC] requinix@php.net
-Status: Verified +Status: Open
 [2019-09-24 10:57 UTC] cmb@php.net
Well, the ISO 8061 *draft*[1] indeed allows zero recurrences:

  recurringIndicator = "R", {digit}, "/" ;
  digit = positiveDigit | "0" ;

This does not necessarily imply, though, that the final standard
also allows zero recurrences.

[1] <https://web.archive.org/web/20171020084445/https://www.loc.gov/standards/datetime/ISO_DIS%208601-1.pdf>
 [2019-09-24 20:37 UTC] will dot baumbach at iselinc dot com
>This does not necessarily imply, though, that the final standard also allows zero recurrences.

Without purchasing the latest 2019 standard. In the 2000 final draft and 2016 draft, published in 2000 and 2019 respectively.

http://www.pvv.org/~nsaa/8601v2000.pdf
https://web.archive.org/web/20171020084445/https://www.loc.gov/standards/datetime/ISO_DIS%208601-1.pdf

"[n] represents digit(s), constituting a positive integer or zero;"
"Rn/..." 
"R/..."

Since the definition and format was specified identically in both drafts, I would say it is safe to imply it also carried over into the published 2000 and 2019 final standards.

If copyrights permit and would help the PHP community, I would gladly purchase an applicable published standard.
 
PHP Copyright © 2001-2019 The PHP Group
All rights reserved.
Last updated: Sun Nov 17 12:01:34 2019 UTC