Skip to content

Eloquent's fill(...) should recognize timezones if provided #42447

@bilogic

Description

@bilogic
  • PHP version: 7.4.28
  • Laravel version: 8.83.13
  • MySQL version: 8.0.29-0ubuntu0.21.10.2
  • MySQL Client version: mysqlnd 7.4.28
  • databaseEngine version: mysql

Description:

Eloquent's fill(...) should recognize timezones if provided.

Since Laravel 7+, toArray() now returns datetimes in ISO-8601 format and that's ok.
However, ISO-8601 is not just time, it is time + zone.

See how Carbon adjusts it's zone (from +8 to 0) when parsing an ISO-8601 string

>>> $a = \Carbon\Carbon::now();
=> Carbon\Carbon @1652966760 {#6225
     date: 2022-05-19 21:26:00.506481 Asia/Singapore (+08:00),
   }

>>> $a = $a->parse("2022-04-05T11:52:53.000000Z");
=> Carbon\Carbon @1649159573 {#6230
     date: 2022-04-05 11:52:53.0 +00:00,
   }

>>> $a->getTimezone()
=> Carbon\CarbonTimeZone {#6231
     timezone: +00:00,
   }

>>>

Steps To Reproduce:

In contrast, when a model's created_at is assigned an ISO-8601 string, it only assigns the time and drops the zone.

>>> $u = \App\Models\User::make()->fill(['created_at'=>'2022-04-05T11:52:53.000000Z']);
=> App\Models\User {#6225
     created_at: "2022-04-05 11:52:53",
   }

>>> $u->created_at->getTimezone()
=> Carbon\CarbonTimeZone {#6207
     timezone: Asia/Singapore (+08:00),
   }

>>>

Why it matters

  • toArray() is a convenient way for movement of data out of the database
  • We ought to be able to import that same array back into the DB by using fill(...)
  • However, as illustrated above, the zone information is ignored and this causes problems for everyone except those on +00:00
  • The solution should be as follows:
  1. Since an ISO-8601 string is provided, the time value should be shfited to match the DB's timezone, i.e. +08:00
  2. This shifted time is then filled into created_at
  3. If a non ISO-8601 string is provided or a date/time without timezone is provided, then the current behavior makes sense, i.e. just write the value into created_at regardless of the DB's timezone

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions