Skip to content

Commit

Permalink
Merge pull request #8661 from kenjis/fix-time-diff-DST
Browse files Browse the repository at this point in the history
fix: Time::difference() DST bug
  • Loading branch information
kenjis authored Mar 29, 2024
2 parents 87652c9 + f99ca6a commit 8e64913
Show file tree
Hide file tree
Showing 6 changed files with 76 additions and 9 deletions.
17 changes: 15 additions & 2 deletions system/I18n/TimeTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -1069,8 +1069,21 @@ public function humanize()
*/
public function difference($testTime, ?string $timezone = null)
{
$testTime = $this->getUTCObject($testTime, $timezone);
$ourTime = $this->getUTCObject($this);
if (is_string($testTime)) {
$timezone = ($timezone !== null) ? new DateTimeZone($timezone) : $this->timezone;
$testTime = new DateTime($testTime, $timezone);
} elseif ($testTime instanceof self) {
$testTime = $testTime->toDateTime();
}

assert($testTime instanceof DateTime);

if ($this->timezone->getOffset($this) !== $testTime->getTimezone()->getOffset($this)) {
$testTime = $this->getUTCObject($testTime, $timezone);
$ourTime = $this->getUTCObject($this);
} else {
$ourTime = $this->toDateTime();
}

return new TimeDifference($ourTime, $testTime);
}
Expand Down
20 changes: 14 additions & 6 deletions tests/system/I18n/TimeDifferenceTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ public function testHumanizeMonthsForward(): void
$current = Time::parse('March 1, 2017', 'America/Chicago');
$diff = $current->difference('May 1, 2017', 'America/Chicago');

$this->assertSame('in 1 month', $diff->humanize('en'));
$this->assertSame('in 2 months', $diff->humanize('en'));
}

public function testHumanizeDaysSingle(): void
Expand Down Expand Up @@ -211,12 +211,20 @@ public function testHumanizeWeeksPlural(): void
$this->assertSame('2 weeks ago', $diff->humanize('en'));
}

public function testHumanizeWeeksForward(): void
public function testHumanizeWeeksForwardDST(): void
{
$current = Time::parse('March 10, 2017', 'America/Chicago');
$diff = $current->difference('March 18, 2017', 'America/Chicago');

$this->assertSame('in 1 week', $diff->humanize('en'));
$this->assertSame('in 2 weeks', $diff->humanize('en'));
}

public function testHumanizeWeeksForwardUTC(): void
{
$current = Time::parse('2017-03-10');
$diff = $current->difference('2017-03-18');

$this->assertSame('in 2 weeks', $diff->humanize('en'));
}

public function testHumanizeNoDifference(): void
Expand All @@ -238,14 +246,14 @@ public function testGetterUTC(): void
$this->assertNull($diff->nonsense);
}

public function testGetterChicagoTime(): void
public function testGetterDST(): void
{
$current = Time::parse('March 10, 2017', 'America/Chicago');
$diff = $current->difference('March 18, 2017', 'America/Chicago');

// Daylight Saving Time had begun since Sun, 12 Mar, 02:00.
$this->assertSame(7, $diff->getDays());
$this->assertSame(7, $diff->days);
$this->assertSame(8, $diff->getDays());
$this->assertSame(8, $diff->days);

// The raw value does not take Daylight Saving Time into account.
$this->assertSame(-8, (int) round($diff->getDays(true)));
Expand Down
5 changes: 5 additions & 0 deletions user_guide_src/source/changelogs/v4.4.7.rst
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,11 @@ Release Date: Unreleased
BREAKING
********

- In previous versions, when comparing dates with ``Time::difference()``,
unexpected results were returned if the date included a day different from 24
hours due to Daylight Saving Time (DST). This bug has been fixed. See
:ref:`Note in Times and Dates <time-viewing-differences>` for details.

***************
Message Changes
***************
Expand Down
15 changes: 15 additions & 0 deletions user_guide_src/source/installation/upgrade_447.rst
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,21 @@ The error page has been updated. Please update the following files:
Breaking Changes
****************

Time::difference() and DST
==========================

In previous versions, when comparing dates with ``Time::difference()``, unexpected
results were returned if the date included a day different from 24 hours due to
Daylight Saving Time (DST). See :ref:`Note in Times and Dates <time-viewing-differences>`
for details.

This bug has been fixed, so date comparisons will now be shifted by one day in
such cases.

In the unlikely event that you wish to maintain the behavior of the previous
versions, change the time zone of both dates being compared to UTC before passing
them to ``Time::difference()``.

*********************
Breaking Enhancements
*********************
Expand Down
15 changes: 14 additions & 1 deletion user_guide_src/source/libraries/time.rst
Original file line number Diff line number Diff line change
Expand Up @@ -365,11 +365,15 @@ Works exactly the same as ``isBefore()`` except checks if the time is after the

.. literalinclude:: time/037.php

.. _time-viewing-differences:

Viewing Differences
===================

To compare two Times directly, you would use the ``difference()`` method, which returns a ``CodeIgniter\I18n\TimeDifference``
instance. The first parameter is either a Time instance, a DateTime instance, or a string with the date/time. If
instance.

The first parameter is either a Time instance, a DateTime instance, or a string with the date/time. If
a string is passed in the first parameter, the second parameter can be a timezone string:

.. literalinclude:: time/038.php
Expand All @@ -380,6 +384,15 @@ the original time:

.. literalinclude:: time/039.php

.. note:: Prior to v4.4.7, Time always converted the time zones to UTC before
comparison. This could lead to unexpected results when containing a day
differed from 24 hours due to Daylight Saving Time (DST).

Starting with v4.4.7, when comparing date/times that are in the same
time zone, the comparison is performed as is, without conversion to UTC.

.. literalinclude:: time/042.php

You can use either ``getX()`` methods, or access the calculate values as if they were properties:

.. literalinclude:: time/040.php
Expand Down
13 changes: 13 additions & 0 deletions user_guide_src/source/libraries/time/042.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?php

use CodeIgniter\I18n\Time;

// 31 Mar 2024 - Daylight Saving Time Starts
$current = Time::parse('2024-03-31', 'Europe/Madrid');
$test = Time::parse('2024-04-01', 'Europe/Madrid');

$diff = $current->difference($test);

echo $diff->getDays();
// 0 in v4.4.6 or before
// 1 in v4.4.7 or later

0 comments on commit 8e64913

Please sign in to comment.