Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: Time::difference() DST bug #8661

Merged
merged 5 commits into from
Mar 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 @@ -362,11 +362,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 @@ -377,6 +381,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
Loading