diff --git a/CHANGELOG.md b/CHANGELOG.md index 269992de8..b536def07 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,10 @@ # Changelog All notable changes to this project will be documented in this file. +## [4.1.3] - unreleased + +* Fix the timezone of `datetime` fields when they are read from the database by @GromNaN in [#2739](https://github.com/mongodb/laravel-mongodb/pull/2739) + ## [4.1.2] - 2024-02-22 * Fix support for subqueries using the query builder by @GromNaN in [#2717](https://github.com/mongodb/laravel-mongodb/pull/2717) diff --git a/src/Eloquent/Model.php b/src/Eloquent/Model.php index 80a29e4fa..dbf7579cd 100644 --- a/src/Eloquent/Model.php +++ b/src/Eloquent/Model.php @@ -6,6 +6,7 @@ use Carbon\CarbonInterface; use DateTimeInterface; +use DateTimeZone; use Illuminate\Contracts\Queue\QueueableCollection; use Illuminate\Contracts\Queue\QueueableEntity; use Illuminate\Contracts\Support\Arrayable; @@ -30,6 +31,7 @@ use function array_values; use function class_basename; use function count; +use function date_default_timezone_get; use function explode; use function func_get_args; use function in_array; @@ -137,7 +139,8 @@ protected function asDateTime($value) { // Convert UTCDateTime instances to Carbon. if ($value instanceof UTCDateTime) { - return Date::instance($value->toDateTime()); + return Date::instance($value->toDateTime()) + ->setTimezone(new DateTimeZone(date_default_timezone_get())); } return parent::asDateTime($value); diff --git a/tests/ModelTest.php b/tests/ModelTest.php index e34e3d6f2..ec1579869 100644 --- a/tests/ModelTest.php +++ b/tests/ModelTest.php @@ -31,6 +31,7 @@ use function abs; use function array_keys; use function array_merge; +use function date_default_timezone_set; use function get_debug_type; use function hex2bin; use function sleep; @@ -38,6 +39,8 @@ use function strlen; use function time; +use const DATE_ATOM; + class ModelTest extends TestCase { public function tearDown(): void @@ -670,6 +673,33 @@ public function testUnsetDotAttributesAndSet(): void $this->assertSame(['note2' => 'DEF', 'note1' => 'ABC'], $user->notes); } + public function testDateUseLocalTimeZone(): void + { + // The default timezone is reset to UTC before every test in OrchestraTestCase + $tz = 'Australia/Sydney'; + date_default_timezone_set($tz); + + $date = new DateTime('1965/03/02 15:30:10'); + $user = User::create(['birthday' => $date]); + $this->assertInstanceOf(Carbon::class, $user->birthday); + $this->assertEquals($tz, $user->birthday->getTimezone()->getName()); + $user->save(); + + $user = User::find($user->_id); + $this->assertEquals($date, $user->birthday); + $this->assertEquals($tz, $user->birthday->getTimezone()->getName()); + $this->assertSame('1965-03-02T15:30:10+10:00', $user->birthday->format(DATE_ATOM)); + + $tz = 'America/New_York'; + date_default_timezone_set($tz); + $user = User::find($user->_id); + $this->assertEquals($date, $user->birthday); + $this->assertEquals($tz, $user->birthday->getTimezone()->getName()); + $this->assertSame('1965-03-02T00:30:10-05:00', $user->birthday->format(DATE_ATOM)); + + date_default_timezone_set('UTC'); + } + public function testDates(): void { $user = User::create(['name' => 'John Doe', 'birthday' => new DateTime('1965/1/1')]);