Skip to content

Commit 5150c45

Browse files
committed
Merge remote-tracking branch 'upstream/develop' into 4.5
Conflicts: system/Model.php
2 parents 9820c31 + 404e50b commit 5150c45

File tree

9 files changed

+128
-11
lines changed

9 files changed

+128
-11
lines changed

system/Database/BaseBuilder.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1534,7 +1534,7 @@ protected function _limit(string $sql, bool $offsetIgnore = false): string
15341534
/**
15351535
* Allows key/value pairs to be set for insert(), update() or replace().
15361536
*
1537-
* @param array|object|string $key Field name, or an array of field/value pairs
1537+
* @param array|object|string $key Field name, or an array of field/value pairs, or an object
15381538
* @param mixed $value Field value, if $key is a single field
15391539
* @param bool|null $escape Whether to escape values
15401540
*

system/I18n/TimeTrait.php

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1071,8 +1071,21 @@ public function humanize()
10711071
*/
10721072
public function difference($testTime, ?string $timezone = null)
10731073
{
1074-
$testTime = $this->getUTCObject($testTime, $timezone);
1075-
$ourTime = $this->getUTCObject($this);
1074+
if (is_string($testTime)) {
1075+
$timezone = ($timezone !== null) ? new DateTimeZone($timezone) : $this->timezone;
1076+
$testTime = new DateTime($testTime, $timezone);
1077+
} elseif ($testTime instanceof self) {
1078+
$testTime = $testTime->toDateTime();
1079+
}
1080+
1081+
assert($testTime instanceof DateTime);
1082+
1083+
if ($this->timezone->getOffset($this) !== $testTime->getTimezone()->getOffset($this)) {
1084+
$testTime = $this->getUTCObject($testTime, $timezone);
1085+
$ourTime = $this->getUTCObject($this);
1086+
} else {
1087+
$ourTime = $this->toDateTime();
1088+
}
10761089

10771090
return new TimeDifference($ourTime, $testTime);
10781091
}

system/Model.php

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
use Config\Database;
2929
use Config\Feature;
3030
use ReflectionException;
31+
use stdClass;
3132

3233
/**
3334
* The Model class extends BaseModel and provides additional
@@ -715,14 +716,18 @@ public function builder(?string $table = null)
715716
* data here. This allows it to be used with any of the other
716717
* builder methods and still get validated data, like replace.
717718
*
718-
* @param array|object|string $key Field name, or an array of field/value pairs
719+
* @param array|object|string $key Field name, or an array of field/value pairs, or an object
719720
* @param bool|float|int|object|string|null $value Field value, if $key is a single field
720721
* @param bool|null $escape Whether to escape values
721722
*
722723
* @return $this
723724
*/
724725
public function set($key, $value = '', ?bool $escape = null)
725726
{
727+
if (is_object($key)) {
728+
$key = $key instanceof stdClass ? (array) $key : $this->objectToArray($key);
729+
}
730+
726731
$data = is_array($key) ? $key : [$key => $value];
727732

728733
foreach (array_keys($data) as $k) {

tests/system/I18n/TimeDifferenceTest.php

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@ public function testHumanizeMonthsForward(): void
122122
$current = Time::parse('March 1, 2017', 'America/Chicago');
123123
$diff = $current->difference('May 1, 2017', 'America/Chicago');
124124

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

128128
public function testHumanizeDaysSingle(): void
@@ -213,12 +213,20 @@ public function testHumanizeWeeksPlural(): void
213213
$this->assertSame('2 weeks ago', $diff->humanize('en'));
214214
}
215215

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

221-
$this->assertSame('in 1 week', $diff->humanize('en'));
221+
$this->assertSame('in 2 weeks', $diff->humanize('en'));
222+
}
223+
224+
public function testHumanizeWeeksForwardUTC(): void
225+
{
226+
$current = Time::parse('2017-03-10');
227+
$diff = $current->difference('2017-03-18');
228+
229+
$this->assertSame('in 2 weeks', $diff->humanize('en'));
222230
}
223231

224232
public function testHumanizeNoDifference(): void
@@ -240,14 +248,14 @@ public function testGetterUTC(): void
240248
$this->assertNull($diff->nonsense);
241249
}
242250

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

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

252260
// The raw value does not take Daylight Saving Time into account.
253261
$this->assertSame(-8, (int) round($diff->getDays(true)));

tests/system/Models/UpdateModelTest.php

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -382,6 +382,51 @@ public function testUpdateWithEntityNoAllowedFields(): void
382382
$this->model->update($id, $entity);
383383
}
384384

385+
public function testUpdateSetObject(): void
386+
{
387+
$this->createModel(UserModel::class);
388+
389+
$object = new stdClass();
390+
$object->name = 'Jones Martin';
391+
$object->email = '[email protected]';
392+
$object->country = 'India';
393+
394+
/** @var int|string $id */
395+
$id = $this->model->insert($object);
396+
397+
/** @var stdClass $object */
398+
$object = $this->model->find($id);
399+
$object->name = 'John Smith';
400+
401+
$return = $this->model->where('id', $id)->set($object)->update();
402+
403+
$this->assertTrue($return);
404+
}
405+
406+
public function testUpdateSetEntity(): void
407+
{
408+
$this->createModel(UserModel::class);
409+
410+
$object = new stdClass();
411+
$object->id = 1;
412+
$object->name = 'Jones Martin';
413+
$object->email = '[email protected]';
414+
$object->country = 'India';
415+
416+
$id = $this->model->insert($object);
417+
418+
$entity = new Entity([
419+
'id' => 1,
420+
'name' => 'John Smith',
421+
'email' => '[email protected]',
422+
'country' => 'India',
423+
]);
424+
425+
$return = $this->model->where('id', $id)->set($entity)->update();
426+
427+
$this->assertTrue($return);
428+
}
429+
385430
public function testUpdateEntityWithPrimaryKeyCast(): void
386431
{
387432
if (

user_guide_src/source/changelogs/v4.4.7.rst

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,11 @@ Release Date: Unreleased
1414
BREAKING
1515
********
1616

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

user_guide_src/source/installation/upgrade_447.rst

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,21 @@ The error page has been updated. Please update the following files:
2828
Breaking Changes
2929
****************
3030

31+
Time::difference() and DST
32+
==========================
33+
34+
In previous versions, when comparing dates with ``Time::difference()``, unexpected
35+
results were returned if the date included a day different from 24 hours due to
36+
Daylight Saving Time (DST). See :ref:`Note in Times and Dates <time-viewing-differences>`
37+
for details.
38+
39+
This bug has been fixed, so date comparisons will now be shifted by one day in
40+
such cases.
41+
42+
In the unlikely event that you wish to maintain the behavior of the previous
43+
versions, change the time zone of both dates being compared to UTC before passing
44+
them to ``Time::difference()``.
45+
3146
*********************
3247
Breaking Enhancements
3348
*********************

user_guide_src/source/libraries/time.rst

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -365,11 +365,15 @@ Works exactly the same as ``isBefore()`` except checks if the time is after the
365365

366366
.. literalinclude:: time/037.php
367367

368+
.. _time-viewing-differences:
369+
368370
Viewing Differences
369371
===================
370372

371373
To compare two Times directly, you would use the ``difference()`` method, which returns a ``CodeIgniter\I18n\TimeDifference``
372-
instance. The first parameter is either a Time instance, a DateTime instance, or a string with the date/time. If
374+
instance.
375+
376+
The first parameter is either a Time instance, a DateTime instance, or a string with the date/time. If
373377
a string is passed in the first parameter, the second parameter can be a timezone string:
374378

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

381385
.. literalinclude:: time/039.php
382386

387+
.. note:: Prior to v4.4.7, Time always converted the time zones to UTC before
388+
comparison. This could lead to unexpected results when containing a day
389+
differed from 24 hours due to Daylight Saving Time (DST).
390+
391+
Starting with v4.4.7, when comparing date/times that are in the same
392+
time zone, the comparison is performed as is, without conversion to UTC.
393+
394+
.. literalinclude:: time/042.php
395+
383396
You can use either ``getX()`` methods, or access the calculate values as if they were properties:
384397

385398
.. literalinclude:: time/040.php
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<?php
2+
3+
use CodeIgniter\I18n\Time;
4+
5+
// 31 Mar 2024 - Daylight Saving Time Starts
6+
$current = Time::parse('2024-03-31', 'Europe/Madrid');
7+
$test = Time::parse('2024-04-01', 'Europe/Madrid');
8+
9+
$diff = $current->difference($test);
10+
11+
echo $diff->getDays();
12+
// 0 in v4.4.6 or before
13+
// 1 in v4.4.7 or later

0 commit comments

Comments
 (0)