Framework: toArray uses incorrect timezone.

Created on 4 Mar 2020  路  7Comments  路  Source: laravel/framework

  • Laravel Version: 7.0
  • PHP Version: 7.3
  • Database Driver & Version: Mysql 5.6

Description:

When using the toArray() method on a modal, it does not show the timestamps in the correct timezone.

Steps To Reproduce:

  1. Set the app.php timezone to America/Toronto
  2. Insert some rows for any model you want
  3. Create a blade file with this code for the model:

    created_at: {{ $model->created_at }}
    <br><br>
    via array: {{ print_r($model->toArray(), true) }}
    

You can clearly see that $model->created_at is showing the correct date via the exact database value, and for whatever reason toArray is deciding to change it to UTC.

Most helpful comment

@viirre @taylorotwell I really think it is wrong. Carbon::toJSON() method will create a copy of current $date and set it to utc(), ignoring the app.timezone. So non-UTC dates will have a wrong output when toArray() or similar is called. It is really intentional?

A simple solution is modify how serializeDate() works by calling toISOString(true) instead of toJSON(). The true on toISOString(true) means "do not set timezone to UTF, keep as is".

All 7 comments

That's intentional: https://laravel.com/docs/7.x/upgrade#date-serialization

杩欐槸鏁呮剰鐨勶細https : //laravel.com/docs/7.x/upgrade#date-serialization

But the time zone is wrong. The real-time environment variable is set

This is expected. Carbon will format the (string) typecast according to its __toString function and the toArray method will serialize it with the new serialization.

Note the upgrade guide specifies how to keep the old behavior if you want.

OK thanks. I just ended up using an accessor for now.

I know this issue is closed but I'm trying anyway with a similar problem caused by this change.

There are some cases where this change might cause issues for a lot of apps, ours included. Consider:

        $invoiceModel = Invoice::make(['number' => 'foobar', 'date' => '2020-03-01']);
        $customer->invoices()->updateOrCreate(
            ['number' => $invoiceModel->number],
            $invoiceModel->attributesToArray()
        );

If the Invoice model has a date cast for the the date attribute, the date will be saved as 2020-02-29 instead of the correct 2020-03-01 because our timezone is set to Europe/Stockholm and not UTC.

The solution is to either set the timezone to UTC (which of course is not an option), set the cast as date:y-m-d or use the suggested upgrade guide solution of declaring our own serializedDate method on the model.

Is this really intended behaviour forattributesToArray/toArray regarding the date cast?

@viirre @taylorotwell I really think it is wrong. Carbon::toJSON() method will create a copy of current $date and set it to utc(), ignoring the app.timezone. So non-UTC dates will have a wrong output when toArray() or similar is called. It is really intentional?

A simple solution is modify how serializeDate() works by calling toISOString(true) instead of toJSON(). The true on toISOString(true) means "do not set timezone to UTF, keep as is".

Was this page helpful?
0 / 5 - 0 ratings