Skip to content

Commit 7e58971

Browse files
authored
Merge pull request #9106 from kenjis/fix-Time-setTimestamp
fix: Time::setTimestamp()'s different behavior than DateTime
2 parents 0a15e7b + 3884480 commit 7e58971

File tree

9 files changed

+107
-23
lines changed

9 files changed

+107
-23
lines changed

system/I18n/TimeLegacy.php

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@
1414
namespace CodeIgniter\I18n;
1515

1616
use DateTime;
17+
use Exception;
18+
use ReturnTypeWillChange;
1719

1820
/**
1921
* Legacy Time class.
@@ -47,4 +49,21 @@
4749
class TimeLegacy extends DateTime
4850
{
4951
use TimeTrait;
52+
53+
/**
54+
* Returns a new instance with the date set to the new timestamp.
55+
*
56+
* @param int $timestamp
57+
*
58+
* @return static
59+
*
60+
* @throws Exception
61+
*/
62+
#[ReturnTypeWillChange]
63+
public function setTimestamp($timestamp)
64+
{
65+
$time = date('Y-m-d H:i:s', $timestamp);
66+
67+
return static::parse($time, $this->timezone, $this->locale);
68+
}
5069
}

system/I18n/TimeTrait.php

Lines changed: 0 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -685,23 +685,6 @@ public function setTimezone($timezone)
685685
return static::createFromInstance($this->toDateTime()->setTimezone($timezone), $this->locale);
686686
}
687687

688-
/**
689-
* Returns a new instance with the date set to the new timestamp.
690-
*
691-
* @param int $timestamp
692-
*
693-
* @return static
694-
*
695-
* @throws Exception
696-
*/
697-
#[ReturnTypeWillChange]
698-
public function setTimestamp($timestamp)
699-
{
700-
$time = date('Y-m-d H:i:s', $timestamp);
701-
702-
return static::parse($time, $this->timezone, $this->locale);
703-
}
704-
705688
// --------------------------------------------------------------------
706689
// Add/Subtract
707690
// --------------------------------------------------------------------

tests/system/I18n/TimeTest.php

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
use CodeIgniter\Test\CIUnitTestCase;
1919
use Config\App;
2020
use DateTime;
21+
use DateTimeImmutable;
2122
use DateTimeZone;
2223
use IntlDateFormatter;
2324
use Locale;
@@ -719,13 +720,28 @@ public function testSetTimezone(): void
719720

720721
public function testSetTimestamp(): void
721722
{
722-
$time = Time::parse('May 10, 2017', 'America/Chicago');
723-
$stamp = strtotime('April 1, 2017');
724-
$time2 = $time->setTimestamp($stamp);
723+
$time1 = Time::parse('May 10, 2017', 'America/Chicago');
724+
725+
$stamp = strtotime('2017-04-01'); // We use UTC as the default timezone.
726+
$time2 = $time1->setTimestamp($stamp);
725727

726728
$this->assertInstanceOf(Time::class, $time2);
727-
$this->assertNotSame($time, $time2);
728-
$this->assertSame('2017-04-01 00:00:00', $time2->toDateTimeString());
729+
$this->assertSame('2017-05-10 00:00:00 -05:00', $time1->format('Y-m-d H:i:s P'));
730+
$this->assertSame('2017-03-31 19:00:00 -05:00', $time2->format('Y-m-d H:i:s P'));
731+
}
732+
733+
public function testSetTimestampDateTimeImmutable(): void
734+
{
735+
$time1 = new DateTimeImmutable(
736+
'May 10, 2017',
737+
new DateTimeZone('America/Chicago')
738+
);
739+
740+
$stamp = strtotime('2017-04-01'); // We use UTC as the default timezone.
741+
$time2 = $time1->setTimestamp($stamp);
742+
743+
$this->assertSame('2017-05-10 00:00:00 -05:00', $time1->format('Y-m-d H:i:s P'));
744+
$this->assertSame('2017-03-31 19:00:00 -05:00', $time2->format('Y-m-d H:i:s P'));
729745
}
730746

731747
public function testToDateString(): void

user_guide_src/source/changelogs/v4.6.0.rst

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,12 @@ Time with Microseconds
7171
Fixed bugs that some methods in ``Time`` to lose microseconds have been fixed.
7272
See :ref:`Upgrading Guide <upgrade-460-time-keeps-microseconds>` for details.
7373

74+
Time::setTimestamp()
75+
--------------------
76+
77+
``Time::setTimestamp()`` behavior has been fixed.
78+
See :ref:`Upgrading Guide <upgrade-460-time-set-timestamp>` for details.
79+
7480
.. _v460-interface-changes:
7581

7682
Interface Changes

user_guide_src/source/installation/upgrade_460.rst

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,25 @@ Also, methods that returns an ``int`` still lose the microseconds.
8585
.. literalinclude:: upgrade_460/005.php
8686
:lines: 2-
8787

88+
.. _upgrade-460-time-set-timestamp:
89+
90+
Time::setTimestamp() Behavior Fix
91+
=================================
92+
93+
In previous versions, if you call ``Time::setTimestamp()`` on a Time instance with
94+
a timezone other than the default timezone might return a Time instance with the
95+
wrong date/time.
96+
97+
This bug has been fixed, and it now behaves in the same way as ``DateTimeImmutable``:
98+
99+
.. literalinclude:: upgrade_460/008.php
100+
:lines: 2-
101+
102+
Note that if you use the default timezone, the behavior is not changed:
103+
104+
.. literalinclude:: upgrade_460/009.php
105+
:lines: 2-
106+
88107
.. _upgrade-460-registrars-with-dirty-hack:
89108

90109
Registrars with Dirty Hack
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
<?php
2+
3+
use CodeIgniter\I18n\Time;
4+
5+
// The Application Timezone is "UTC".
6+
7+
// Set $time1 timezone to "America/Chicago".
8+
$time1 = Time::parse('2024-08-20', 'America/Chicago');
9+
10+
// The timestamp is "2024-08-20 00:00" in "UTC".
11+
$stamp = strtotime('2024-08-20'); // 1724112000
12+
13+
// But $time2 timezone is "America/Chicago".
14+
$time2 = $time1->setTimestamp($stamp);
15+
16+
echo $time2->format('Y-m-d H:i:s P');
17+
// Before: 2024-08-20 00:00:00 -05:00
18+
// After: 2024-08-19 19:00:00 -05:00
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
<?php
2+
3+
use CodeIgniter\I18n\Time;
4+
5+
// The Application Timezone is "America/Chicago".
6+
7+
// $time1 timezone is "America/Chicago".
8+
$time1 = Time::parse('2024-08-20');
9+
10+
// The timestamp is "2024-08-20 00:00" in "America/Chicago".
11+
$stamp = strtotime('2024-08-20'); // 1724130000
12+
13+
// $time2 timezone is also "America/Chicago".
14+
$time2 = $time1->setTimestamp($stamp);
15+
16+
echo $time2->format('Y-m-d H:i:s P');
17+
// Before: 2024-08-20 00:00:00 -05:00
18+
// After: 2024-08-20 00:00:00 -05:00

user_guide_src/source/libraries/time.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -314,6 +314,9 @@ Returns a new instance with the date set to the new timestamp:
314314

315315
.. literalinclude:: time/030.php
316316

317+
.. note:: Prior to v4.6.0, due to a bug, this method might return incorrect
318+
date/time. See :ref:`Upgrading Guide <upgrade-460-time-set-timestamp>` for details.
319+
317320
Modifying the Value
318321
===================
319322

user_guide_src/source/libraries/time/030.php

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@
22

33
use CodeIgniter\I18n\Time;
44

5-
$time = Time::parse('May 10, 2017', 'America/Chicago');
5+
// The Application Timezone is "America/Chicago".
6+
7+
$time = Time::parse('May 10, 2017');
68
$time2 = $time->setTimestamp(strtotime('April 1, 2017'));
79

810
echo $time->toDateTimeString(); // 2017-05-10 00:00:00

0 commit comments

Comments
 (0)