Skip to content

Time zone bug with \DateTimeInterface::diff() #9866

Closed

Description

@jack-worman

Description

The following code:

<?php

function getYearsBetween(
    \DateTimeImmutable $startDate,
    \DateTimeImmutable $endDate,
): int {
    $dateInterval = $startDate->diff($endDate, true);
    return $dateInterval->y;
}

$start = new \DateTimeImmutable('2000-11-01 09:29:22.907606', new \DateTimeZone('America/Chicago'));
$end = new \DateTimeImmutable('2022-06-06 11:00:00.000000', new \DateTimeZone('America/New_York'));
$result = getYearsBetween($start, $end);
var_export($result);

Resulted in this output:

-22

But I expected this output instead:

21

There seems to be a timezone issue that breaks \DateIntervals
Works (same time zones): https://3v4l.org/RK34h
Does not work (different time zones): https://3v4l.org/nmPAj

In the mean time, I will be ensuring both \DateTimeImmutables are in the same timezone before calling ->diff()

PHP Version

>= 8.1.10

Operating System

No response

Activity

  1. changed the title [-]Bug introduced in PHP 8.[/-] [+]Time zone bug with \DateTimeInterface::diff()[/+] on Nov 1, 2022
  2. heiglandreas commented on Nov 1, 2022

    @heiglandreas
    Contributor

    That looks like the documentation of the parameter absolute is a bit ... off?

  3. hormus commented on Nov 4, 2022

    @hormus
    The return value more specifically represents the clock-time interval to apply to the original object ($this or $originObject) to arrive at the $targetObject. This process is not always reversible.
    

    Without absolute

    <?php
    
    $start = new \DateTime('2000-11-01 09:29:22.907606', new \DateTimeZone('America/Chicago'));
    $end = new \DateTime('2022-06-06 11:00:00.000000', new \DateTimeZone('America/New_York'));
    $result = $start->diff($end);
    var_export($result->y);
    
    ?>

    Yes bug, DateTimeImmutable from php 5.5.0, diff from php 5.3.0 expected result is 21.

    <?php
    $utc = new \DateTimeZone('UTC');
    $london = new \DateTimeZone('Europe/London');
    
    $test1 = new \DateTime('2018-01-31', $utc);
    $test2 = new \DateTime('2018-03-31 00:00:00', $london);
    
    $dateDiff = $test2->diff($test1); // true absolute Should the interval be forced to be positive
    //$dateDiff = $test1->diff($test2);
    $bugs = array('y' => &$dateDiff->y, 'm' => &$dateDiff->m, 'd' => &$dateDiff->d, 'h' => &$dateDiff->h, 'invert' => &$dateDiff->invert, 'days' => &$dateDiff->days);
    $test3 = new \DateTime('+2 month ' . $test1->format('Y-m-d\\TH:i:s\\Z'));
    
    var_dump($test3->format('Y-m-d H:i:s +00:00'), $bugs, $dateDiff->format('%r%a'));
    
    ?>

    Expected result: (only php < 8.1.10)

    string(26) "2018-03-31 00:00:00 +00:00"
    array(6) {
      ["y"]=>
      int(0)
      ["m"]=>
      int(1)
      ["d"]=>
      int(30)
      ["h"]=>
      int(23)
      ["invert"]=>
      int(1)
      ["days"]=>
      int(58)
    }
    string(3) "-58"
    

    Expected result $dateDiff = $test1->diff($test2): (only php < 8.1.10)

    string(26) "2018-03-31 00:00:00 +00:00"
    array(6) {
      ["y"]=>
      int(0)
      ["m"]=>
      int(1)
      ["d"]=>
      int(27)
      ["h"]=>
      int(23)
      ["invert"]=>
      int(0)
      ["days"]=>
      int(58)
    }
    string(2) "58"
    
  4. added a commit that references this issue on Nov 30, 2022
  5. derickr commented on Nov 30, 2022

    @derickr
    Member

    Now fixed, for PHP 8.1.14 and PHP 8.2.1.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions