Wrong timezone in Laravel 7 after date serialization
Asked Answered
P

1

17

I'm working on a new Laravel 7.1 app (Not an upgrade) But it seems that working with dates serialization loose the timezone.

config/app.php

'timezone' => 'Europe/Zurich',

tinker example

>>> \Carbon\Carbon::parse('2020-06-22')->timezone
=> Carbon\CarbonTimeZone {#3251
     timezone: Europe/Zurich (+01:00),
   }

Laravel 7 uses toJson()

>>> \Carbon\Carbon::parse('2020-06-22')->toJson()
=> "2020-06-21T22:00:00.000000Z"

So, when I parse the date back, I'm not getting the proper date.

>>> new \Carbon\Carbon('2020-06-21T22:00:00.000000Z')
=> Carbon\Carbon @1592776800 {#3266
     date: 2020-06-21 22:00:00.0 +00:00,
     timezone: "Z",
   }

>>> (new \Carbon\Carbon('2020-06-21T22:00:00.000000Z'))->format('Y-m-d')
=> "2020-06-21"


Currently I'm doing it like this

$date = Carbon::parse('2020-06-21T22:00:00.000000Z')
    ->setTimezone(config('app.timezone'));

As alternative I can change the default date format in my models, as stated in the doc

/**
 * Prepare a date for array / JSON serialization.
 *
 * @param  \DateTimeInterface  $date
 * @return string
 */
protected function serializeDate(DateTimeInterface $date)
{
    return $date->toIso8601String(); // 2019-02-01T03:45:27+00:00
}

But it would be preferable that Carbon::parse() and/or new Carbon() take my timezone by default, I guess.-

Prussianism answered 12/3, 2020 at 7:58 Comment(1)
I see the same issue.Docket
B
17

Same problem here.

When upgrading from Laravel 6 -> 7, this was changed. (see here) When serializing, the time is updated from local time to UTC (as per ISO-8601).
But when returning the same sting back to php, the Carbon object does NOT use the ISO-8601 timezone representation.

Problem 1:

When updating to the database, this date is moved with your timezone settings every time.

Problem 2:

When showing the timestamp in the browser, every representation of this field has to be fixed with the (browsers) timezone settings.

Fix:

The upgrade manual proposes a fix.
We use a trait in all our models, so we updated there:

If you would like to keep using the previous behavior you can override the serializeDate method on your model:

use DateTimeInterface;

/**
 * Prepare a date for array / JSON serialization.
 *
 * @param  \DateTimeInterface  $date
 * @return string
 */
protected function serializeDate(DateTimeInterface $date)
{
    return $date->format('Y-m-d H:i:s');
}

It would of course be better to use UTC for everything, but that would require the read-back from JSON (ajax) would utilize the same Timezone settings/differences as the serialization.

Buncombe answered 12/8, 2020 at 13:49 Comment(2)
The proposed fix only works with eloquent models tho. What about DTOs etc.? I'm baffled that there's no way to configure this globally.Magda
@Magda You can use Carbon::serializeUsing() it will change it globallyAutochthonous

© 2022 - 2024 — McMap. All rights reserved.