Skip to content

Commit c710097

Browse files
authored
PHPORM-234 Convert dates in DB Query results (#3119)
Use the current timezone when reading an UTCDateTime
1 parent 5b7ca02 commit c710097

File tree

6 files changed

+47
-19
lines changed

6 files changed

+47
-19
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ All notable changes to this project will be documented in this file.
66
* Remove support for Laravel 10 by @GromNaN in [#3123](https://github.com/mongodb/laravel-mongodb/pull/3123)
77
* **BREAKING CHANGE** Use `id` as an alias for `_id` in commands and queries for compatibility with Eloquent packages by @GromNaN in [#3040](https://github.com/mongodb/laravel-mongodb/pull/3040)
88
* **BREAKING CHANGE** Make Query\Builder return objects instead of array to match Laravel behavior by @GromNaN in [#3107](https://github.com/mongodb/laravel-mongodb/pull/3107)
9+
* **BREAKING CHANGE** In DB query results, convert BSON `UTCDateTime` objects into `Carbon` date with the default timezone by @GromNaN in [#3119](https://github.com/mongodb/laravel-mongodb/pull/3119)
910
* Remove `MongoFailedJobProvider`, replaced by Laravel `DatabaseFailedJobProvider` by @GromNaN in [#3122](https://github.com/mongodb/laravel-mongodb/pull/3122)
1011

1112
## [4.8.0] - 2024-08-27

src/Eloquent/DocumentModel.php

+18-4
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,14 @@
55
namespace MongoDB\Laravel\Eloquent;
66

77
use BackedEnum;
8+
use Carbon\Carbon;
89
use Carbon\CarbonInterface;
910
use DateTimeInterface;
1011
use DateTimeZone;
1112
use Illuminate\Contracts\Queue\QueueableCollection;
1213
use Illuminate\Contracts\Queue\QueueableEntity;
1314
use Illuminate\Contracts\Support\Arrayable;
15+
use Illuminate\Database\Eloquent\Concerns\HasAttributes;
1416
use Illuminate\Database\Eloquent\Model;
1517
use Illuminate\Database\Eloquent\Relations\Relation;
1618
use Illuminate\Support\Arr;
@@ -97,8 +99,14 @@ public function getQualifiedKeyName()
9799
return $this->getKeyName();
98100
}
99101

100-
/** @inheritdoc */
101-
public function fromDateTime($value)
102+
/**
103+
* Convert a DateTimeInterface (including Carbon) to a storable UTCDateTime.
104+
*
105+
* @see HasAttributes::fromDateTime()
106+
*
107+
* @param mixed $value
108+
*/
109+
public function fromDateTime($value): UTCDateTime
102110
{
103111
// If the value is already a UTCDateTime instance, we don't need to parse it.
104112
if ($value instanceof UTCDateTime) {
@@ -113,8 +121,14 @@ public function fromDateTime($value)
113121
return new UTCDateTime($value);
114122
}
115123

116-
/** @inheritdoc */
117-
protected function asDateTime($value)
124+
/**
125+
* Return a timestamp as Carbon object.
126+
*
127+
* @see HasAttributes::asDateTime()
128+
*
129+
* @param mixed $value
130+
*/
131+
protected function asDateTime($value): Carbon
118132
{
119133
// Convert UTCDateTime instances to Carbon.
120134
if ($value instanceof UTCDateTime) {

src/Query/Builder.php

+11-2
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,13 @@
99
use Carbon\CarbonPeriod;
1010
use Closure;
1111
use DateTimeInterface;
12+
use DateTimeZone;
1213
use Illuminate\Database\Query\Builder as BaseBuilder;
1314
use Illuminate\Database\Query\Expression;
1415
use Illuminate\Support\Arr;
1516
use Illuminate\Support\Carbon;
1617
use Illuminate\Support\Collection;
18+
use Illuminate\Support\Facades\Date;
1719
use Illuminate\Support\LazyCollection;
1820
use InvalidArgumentException;
1921
use LogicException;
@@ -39,6 +41,7 @@
3941
use function call_user_func_array;
4042
use function count;
4143
use function ctype_xdigit;
44+
use function date_default_timezone_get;
4245
use function dd;
4346
use function dump;
4447
use function end;
@@ -1660,7 +1663,10 @@ private function aliasIdForResult(array|object $values): array|object
16601663
}
16611664

16621665
foreach ($values as $key => $value) {
1663-
if (is_array($value) || is_object($value)) {
1666+
if ($value instanceof UTCDateTime) {
1667+
$values[$key] = Date::instance($value->toDateTime())
1668+
->setTimezone(new DateTimeZone(date_default_timezone_get()));
1669+
} elseif (is_array($value) || is_object($value)) {
16641670
$values[$key] = $this->aliasIdForResult($value);
16651671
}
16661672
}
@@ -1673,7 +1679,10 @@ private function aliasIdForResult(array|object $values): array|object
16731679
}
16741680

16751681
foreach (get_object_vars($values) as $key => $value) {
1676-
if (is_array($value) || is_object($value)) {
1682+
if ($value instanceof UTCDateTime) {
1683+
$values->{$key} = Date::instance($value->toDateTime())
1684+
->setTimezone(new DateTimeZone(date_default_timezone_get()));
1685+
} elseif (is_array($value) || is_object($value)) {
16771686
$values->{$key} = $this->aliasIdForResult($value);
16781687
}
16791688
}

tests/AuthTest.php

+2-2
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,11 @@
44

55
namespace MongoDB\Laravel\Tests;
66

7+
use Carbon\Carbon;
78
use Illuminate\Auth\Passwords\PasswordBroker;
89
use Illuminate\Support\Facades\Auth;
910
use Illuminate\Support\Facades\DB;
1011
use Illuminate\Support\Facades\Hash;
11-
use MongoDB\BSON\UTCDateTime;
1212
use MongoDB\Laravel\Tests\Models\User;
1313

1414
use function bcrypt;
@@ -63,7 +63,7 @@ function ($actualUser, $actualToken) use ($user, &$token) {
6363
$reminder = DB::table('password_reset_tokens')->first();
6464
$this->assertEquals('john.doe@example.com', $reminder->email);
6565
$this->assertNotNull($reminder->token);
66-
$this->assertInstanceOf(UTCDateTime::class, $reminder->created_at);
66+
$this->assertInstanceOf(Carbon::class, $reminder->created_at);
6767

6868
$credentials = [
6969
'email' => 'john.doe@example.com',

tests/QueryBuilderTest.php

+14-9
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
namespace MongoDB\Laravel\Tests;
66

7+
use Carbon\Carbon;
78
use DateTime;
89
use DateTimeImmutable;
910
use Illuminate\Support\Facades\Date;
@@ -33,7 +34,6 @@
3334
use function md5;
3435
use function sort;
3536
use function strlen;
36-
use function strtotime;
3737

3838
class QueryBuilderTest extends TestCase
3939
{
@@ -676,27 +676,32 @@ public function testUpdateSubdocument()
676676
public function testDates()
677677
{
678678
DB::table('users')->insert([
679-
['name' => 'John Doe', 'birthday' => new UTCDateTime(Date::parse('1980-01-01 00:00:00'))],
680-
['name' => 'Robert Roe', 'birthday' => new UTCDateTime(Date::parse('1982-01-01 00:00:00'))],
681-
['name' => 'Mark Moe', 'birthday' => new UTCDateTime(Date::parse('1983-01-01 00:00:00.1'))],
682-
['name' => 'Frank White', 'birthday' => new UTCDateTime(Date::parse('1960-01-01 12:12:12.1'))],
679+
['name' => 'John Doe', 'birthday' => Date::parse('1980-01-01 00:00:00')],
680+
['name' => 'Robert Roe', 'birthday' => Date::parse('1982-01-01 00:00:00')],
681+
['name' => 'Mark Moe', 'birthday' => Date::parse('1983-01-01 00:00:00.1')],
682+
['name' => 'Frank White', 'birthday' => Date::parse('1975-01-01 12:12:12.1')],
683683
]);
684684

685685
$user = DB::table('users')
686-
->where('birthday', new UTCDateTime(Date::parse('1980-01-01 00:00:00')))
686+
->where('birthday', Date::parse('1980-01-01 00:00:00'))
687687
->first();
688688
$this->assertEquals('John Doe', $user->name);
689689

690690
$user = DB::table('users')
691-
->where('birthday', new UTCDateTime(Date::parse('1960-01-01 12:12:12.1')))
691+
->where('birthday', Date::parse('1975-01-01 12:12:12.1'))
692692
->first();
693+
693694
$this->assertEquals('Frank White', $user->name);
695+
$this->assertInstanceOf(Carbon::class, $user->birthday);
696+
$this->assertSame('1975-01-01 12:12:12.100000', $user->birthday->format('Y-m-d H:i:s.u'));
694697

695698
$user = DB::table('users')->where('birthday', '=', new DateTime('1980-01-01 00:00:00'))->first();
696699
$this->assertEquals('John Doe', $user->name);
700+
$this->assertInstanceOf(Carbon::class, $user->birthday);
701+
$this->assertSame('1980-01-01 00:00:00.000000', $user->birthday->format('Y-m-d H:i:s.u'));
697702

698-
$start = new UTCDateTime(1000 * strtotime('1950-01-01 00:00:00'));
699-
$stop = new UTCDateTime(1000 * strtotime('1981-01-01 00:00:00'));
703+
$start = new UTCDateTime(new DateTime('1950-01-01 00:00:00'));
704+
$stop = new UTCDateTime(new DateTime('1981-01-01 00:00:00'));
700705

701706
$users = DB::table('users')->whereBetween('birthday', [$start, $stop])->get();
702707
$this->assertCount(2, $users);

tests/QueueTest.php

+1-2
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111
use Illuminate\Support\Facades\Queue;
1212
use Illuminate\Support\Str;
1313
use Mockery;
14-
use MongoDB\BSON\UTCDateTime;
1514
use MongoDB\Laravel\Queue\MongoJob;
1615
use MongoDB\Laravel\Queue\MongoQueue;
1716

@@ -197,7 +196,7 @@ public function testFailedJobLogging()
197196
$this->assertSame('test_connection', $failedJob->connection);
198197
$this->assertSame('test_queue', $failedJob->queue);
199198
$this->assertSame('test_payload', $failedJob->payload);
200-
$this->assertEquals(new UTCDateTime(Carbon::now()), $failedJob->failed_at);
199+
$this->assertEquals(Carbon::now(), $failedJob->failed_at);
201200
$this->assertStringStartsWith('Exception: test_exception in ', $failedJob->exception);
202201
}
203202
}

0 commit comments

Comments
 (0)