diff --git a/system/I18n/TimeLegacy.php b/system/I18n/TimeLegacy.php index b62877ec40d6..7dfa0526304a 100644 --- a/system/I18n/TimeLegacy.php +++ b/system/I18n/TimeLegacy.php @@ -14,6 +14,8 @@ namespace CodeIgniter\I18n; use DateTime; +use Exception; +use ReturnTypeWillChange; /** * Legacy Time class. @@ -47,4 +49,21 @@ class TimeLegacy extends DateTime { use TimeTrait; + + /** + * Returns a new instance with the date set to the new timestamp. + * + * @param int $timestamp + * + * @return static + * + * @throws Exception + */ + #[ReturnTypeWillChange] + public function setTimestamp($timestamp) + { + $time = date('Y-m-d H:i:s', $timestamp); + + return static::parse($time, $this->timezone, $this->locale); + } } diff --git a/system/I18n/TimeTrait.php b/system/I18n/TimeTrait.php index 397d9a5a870d..e3808942e335 100644 --- a/system/I18n/TimeTrait.php +++ b/system/I18n/TimeTrait.php @@ -685,23 +685,6 @@ public function setTimezone($timezone) return static::createFromInstance($this->toDateTime()->setTimezone($timezone), $this->locale); } - /** - * Returns a new instance with the date set to the new timestamp. - * - * @param int $timestamp - * - * @return static - * - * @throws Exception - */ - #[ReturnTypeWillChange] - public function setTimestamp($timestamp) - { - $time = date('Y-m-d H:i:s', $timestamp); - - return static::parse($time, $this->timezone, $this->locale); - } - // -------------------------------------------------------------------- // Add/Subtract // -------------------------------------------------------------------- diff --git a/tests/system/I18n/TimeTest.php b/tests/system/I18n/TimeTest.php index 10e38e2110a2..25ae527575d8 100644 --- a/tests/system/I18n/TimeTest.php +++ b/tests/system/I18n/TimeTest.php @@ -18,6 +18,7 @@ use CodeIgniter\Test\CIUnitTestCase; use Config\App; use DateTime; +use DateTimeImmutable; use DateTimeZone; use IntlDateFormatter; use Locale; @@ -719,13 +720,28 @@ public function testSetTimezone(): void public function testSetTimestamp(): void { - $time = Time::parse('May 10, 2017', 'America/Chicago'); - $stamp = strtotime('April 1, 2017'); - $time2 = $time->setTimestamp($stamp); + $time1 = Time::parse('May 10, 2017', 'America/Chicago'); + + $stamp = strtotime('2017-04-01'); // We use UTC as the default timezone. + $time2 = $time1->setTimestamp($stamp); $this->assertInstanceOf(Time::class, $time2); - $this->assertNotSame($time, $time2); - $this->assertSame('2017-04-01 00:00:00', $time2->toDateTimeString()); + $this->assertSame('2017-05-10 00:00:00 -05:00', $time1->format('Y-m-d H:i:s P')); + $this->assertSame('2017-03-31 19:00:00 -05:00', $time2->format('Y-m-d H:i:s P')); + } + + public function testSetTimestampDateTimeImmutable(): void + { + $time1 = new DateTimeImmutable( + 'May 10, 2017', + new DateTimeZone('America/Chicago') + ); + + $stamp = strtotime('2017-04-01'); // We use UTC as the default timezone. + $time2 = $time1->setTimestamp($stamp); + + $this->assertSame('2017-05-10 00:00:00 -05:00', $time1->format('Y-m-d H:i:s P')); + $this->assertSame('2017-03-31 19:00:00 -05:00', $time2->format('Y-m-d H:i:s P')); } public function testToDateString(): void diff --git a/user_guide_src/source/changelogs/v4.6.0.rst b/user_guide_src/source/changelogs/v4.6.0.rst index 51c43456ae28..2077164e8ba1 100644 --- a/user_guide_src/source/changelogs/v4.6.0.rst +++ b/user_guide_src/source/changelogs/v4.6.0.rst @@ -71,6 +71,12 @@ Time with Microseconds Fixed bugs that some methods in ``Time`` to lose microseconds have been fixed. See :ref:`Upgrading Guide ` for details. +Time::setTimestamp() +-------------------- + +``Time::setTimestamp()`` behavior has been fixed. +See :ref:`Upgrading Guide ` for details. + .. _v460-interface-changes: Interface Changes diff --git a/user_guide_src/source/installation/upgrade_460.rst b/user_guide_src/source/installation/upgrade_460.rst index 5cbfd664bf92..da0875849156 100644 --- a/user_guide_src/source/installation/upgrade_460.rst +++ b/user_guide_src/source/installation/upgrade_460.rst @@ -85,6 +85,25 @@ Also, methods that returns an ``int`` still lose the microseconds. .. literalinclude:: upgrade_460/005.php :lines: 2- +.. _upgrade-460-time-set-timestamp: + +Time::setTimestamp() Behavior Fix +================================= + +In previous versions, if you call ``Time::setTimestamp()`` on a Time instance with +a timezone other than the default timezone might return a Time instance with the +wrong date/time. + +This bug has been fixed, and it now behaves in the same way as ``DateTimeImmutable``: + +.. literalinclude:: upgrade_460/008.php + :lines: 2- + +Note that if you use the default timezone, the behavior is not changed: + +.. literalinclude:: upgrade_460/009.php + :lines: 2- + .. _upgrade-460-registrars-with-dirty-hack: Registrars with Dirty Hack diff --git a/user_guide_src/source/installation/upgrade_460/008.php b/user_guide_src/source/installation/upgrade_460/008.php new file mode 100644 index 000000000000..5a778de09c53 --- /dev/null +++ b/user_guide_src/source/installation/upgrade_460/008.php @@ -0,0 +1,18 @@ +setTimestamp($stamp); + +echo $time2->format('Y-m-d H:i:s P'); +// Before: 2024-08-20 00:00:00 -05:00 +// After: 2024-08-19 19:00:00 -05:00 diff --git a/user_guide_src/source/installation/upgrade_460/009.php b/user_guide_src/source/installation/upgrade_460/009.php new file mode 100644 index 000000000000..f00daa0b63b0 --- /dev/null +++ b/user_guide_src/source/installation/upgrade_460/009.php @@ -0,0 +1,18 @@ +setTimestamp($stamp); + +echo $time2->format('Y-m-d H:i:s P'); +// Before: 2024-08-20 00:00:00 -05:00 +// After: 2024-08-20 00:00:00 -05:00 diff --git a/user_guide_src/source/libraries/time.rst b/user_guide_src/source/libraries/time.rst index 9fd986d31421..17af069c8c5f 100644 --- a/user_guide_src/source/libraries/time.rst +++ b/user_guide_src/source/libraries/time.rst @@ -314,6 +314,9 @@ Returns a new instance with the date set to the new timestamp: .. literalinclude:: time/030.php +.. note:: Prior to v4.6.0, due to a bug, this method might return incorrect + date/time. See :ref:`Upgrading Guide ` for details. + Modifying the Value =================== diff --git a/user_guide_src/source/libraries/time/030.php b/user_guide_src/source/libraries/time/030.php index 1e22876e9883..5ca37d326925 100644 --- a/user_guide_src/source/libraries/time/030.php +++ b/user_guide_src/source/libraries/time/030.php @@ -2,7 +2,9 @@ use CodeIgniter\I18n\Time; -$time = Time::parse('May 10, 2017', 'America/Chicago'); +// The Application Timezone is "America/Chicago". + +$time = Time::parse('May 10, 2017'); $time2 = $time->setTimestamp(strtotime('April 1, 2017')); echo $time->toDateTimeString(); // 2017-05-10 00:00:00