php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #75685 DatePeriod returns incorrect iterator count when DST ends
Submitted: 2017-12-14 10:00 UTC Modified: 2021-04-06 18:22 UTC
Votes:3
Avg. Score:5.0 ± 0.0
Reproduced:2 of 2 (100.0%)
Same Version:1 (50.0%)
Same OS:2 (100.0%)
From: markus dot weiland at mapudo dot com Assigned:
Status: Not a bug Package: Date/time related
PHP Version: 7.1.12 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: markus dot weiland at mapudo dot com
New email:
PHP Version: OS:

 

 [2017-12-14 10:00 UTC] markus dot weiland at mapudo dot com
Description:
------------
DatePeriod allows calculating the number of occurrences of a given interval in the specified period (from start to end).

For example, we can obtain the number of hours for each calendar day in the year with `iterator_count()` and print out the number if it is not 24.

Using the example code, we can determine that one hour is missing in 2017 when using this method of calculation and a timezone other than `UTC`.

Test script:
---------------
$interval = new \DateInterval('PT1H'); // plus time one hour
$i = 0;
while ($i < 366) {
    $start = new \DateTime('2017-01-01 00:00:00', new \DateTimeZone('Europe/Berlin'));
    $start->add(new \DateInterval('P'.$i.'D'));

    $end = new \DateTime('2017-01-02 00:00:00', new \DateTimeZone('Europe/Berlin'));
    $end->add(new \DateInterval('P'.$i.'D'));

    $period = new \DatePeriod($start, $interval, $end);
    $diff = iterator_count($period);

    if ($diff != 24) {
        echo sprintf('%s, %d', $start->format(\DateTime::ISO8601), $diff);
    }
    $i++;
}


Expected result:
----------------
We expect to have two values printed to console (i.e. there is one iterator with 23 counts and one with 25 counts):

2017-03-26T00:00:00+0100, 23
2017-10-29T00:00:00+0100, 25

The first, when daylight savings time (DST) starts, the second when DST ends.

This means that the total number of hours in 2017 is 8760 which is equivalent to 365 days of 24 hours.

Actual result:
--------------
Only one value is printed to console:

2017-03-26T00:00:00+0100, 23

This means that the total number of hours in 2017 is 8759 which is _not_ equivalent to 365 days of 24 hours. In other words, one hour is missing, even though 2017 is a "regular" year without leap days, leap seconds, etc..

In contrast, when using `UTC` as timezone in the example code, the year has 8760 hours as expected.

Double-checking with `DateTimeZone::getTransitions()` for `Europe/Berlin` shows that a transition on 2017-10-29 is correctly defined.

Patches

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2020-11-03 11:49 UTC] cmb@php.net
Well, I think the problem is whether

  new DateTime('2017-10-29T02:00:00', new DateTimeZone('Europe/Berlin'))

is CET or CEST.
 [2021-04-06 18:22 UTC] derick@php.net
-Status: Open +Status: Not a bug
 [2021-04-06 18:22 UTC] derick@php.net
Thank you for taking the time to write to us, but this is not
a bug. Please double-check the documentation available at
http://www.php.net/manual/ and the instructions on how to report
a bug at http://bugs.php.net/how-to-report.php

As CMB already alluded too, "2017-10-30T02:00" is CET, so the result is expected:

 php -r "echo (new DateTime('2017-10-29T02:00:00', new DateTimeZone('Europe/Berlin')))->format(\DateTime::ISO8601);"
2017-10-29T02:00:00+0100
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Fri Mar 29 00:01:28 2024 UTC