Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

FabienArr's avatar

Problem with Laravel 12 datetime utc on different field of a model

Hello,

I migrate from Laravel 11 to Laravel 12 in the start of this year, and now i got a problem with the casts function on a model and not on another. For the first model I have this :

protected function casts(): array
{
    return [
        'depot' => 'datetime',
    ];
}

I got with the API the datetime like that : "2025-04-08T15:46:39.000000Z"

For the second model which is users I have this :

    protected function casts(): array
    {
        return [
            'email_verified_at' => 'datetime',
            'validation_parcel' => 'datetime',
        ];
    }

It was ok in Laravel 11, but in Laravel 12 I get this now : "2025-04-08 15:46:39" I don't understand what is wrong with my code.

Thanks for your help.

Regards

0 likes
16 replies
Shivamyadav's avatar

You can directly format the date with your casts .

Like this .

 protected function casts(): array
{
    return [
        'depot' => 'datetime:Y-m-d H:i:s',
    ];
}

FabienArr's avatar

@Shivamyadav Yes but I want this format : "2025-04-08T15:46:39.000000Z" and not this "2025-04-08 15:46:39" But with model user :

protected function casts(): array
{
    return [
        'email_verified_at' => 'datetime',
        'validation_parcel' => 'datetime',
    ];
}

I got "2025-04-08 15:46:39" , it's like the casts of model user doesn't work

Regards

Snapey's avatar

You are not explaining

'I get this...' . How? What is the column type in the database?

Why do you mention API when you are getting data from the database?

FabienArr's avatar

@Snapey The column type in the database is timestamp. Because I have the problem when I get this column with the Laravel API when a I do a REST API request to get the record. I got this as a JSON response :

{
    "success": true,
    "data": {
        "id": 72,
        "name": "DOMAINE",
        "email": "[email protected]",
        "email_verified_at": "2025-02-03 12:03:35",
        "evv": "2900980",
        "relation_id": 12,
        "evv_parent": null,
        "validation_parcellaire": "2025-06-04 16:06:43",
        "created_at": "2023-06-02T18:08:05.000000Z",
        "updated_at": "2025-06-04T14:06:43.000000Z"
    },
    "message": "Utilisateur trouvé."
}

Why for 4 fields timestamp in the database I got 2 with UTC time and the 2 others not ?

FabienArr's avatar

@Snapey I agree with you on the documentation. I want the ISO8601 format, but If I don't put casts it's not an ISO8601, with the casts it's the same. My column name name is good the same in the database and in the model : validation_parcellaire.

I aloso tried this :

    /**
     * Get the attributes that should be cast.
     *
     * @return array<string, string>
     */
    protected function casts(): array
    {
        return [
            'created_at' => 'datetime:Y-m-d',
        ];
    }

it returns :

"created_at": "2023-06-02T18:08:05.000000Z",
Glukinho's avatar

@FabienArr I confirm standard Laravel timestamps (created_at, updated_at) and my custom ones (tested_at) are treated differently when presented as JSON despite they have the same TIMESTAMP definition in DB:

public function test(Request $request)
    {
        return response()->json(User::find(7));
    }
{
  "id": 7,
  "name": "test_name",
  "email": "[email protected]",
  "email_verified_at": null,
  "created_at": "2025-05-23T16:00:55.000000Z",
  "updated_at": "2025-05-23T16:00:56.000000Z",
  "tested_at": "2025-06-05 15:29:52"
}
> show create table users;

CREATE TABLE `users` (
  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
  `name` varchar(255) NOT NULL,
  `email` varchar(255) NOT NULL,
  `email_verified_at` timestamp NULL DEFAULT NULL,
  `password` varchar(255) NOT NULL,
  `remember_token` varchar(100) DEFAULT NULL,
  `created_at` timestamp NULL DEFAULT NULL,
  `updated_at` timestamp NULL DEFAULT NULL,
  `tested_at` timestamp NULL DEFAULT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `users_email_unique` (`email`)
) ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci

I tested on Laravel 12.17.0.

Glukinho's avatar

However this can be fixed easily with cast to datetime:

class User extends Authenticatable
{
    protected function casts(): array
    {
        return [
			// ...
            'tested_at' => 'datetime',
        ];
    }
}
{
  "id": 7,
  "name": "test_name",
  "email": "[email protected]",
  "email_verified_at": null,
  "created_at": "2025-05-23T16:00:55.000000Z",
  "updated_at": "2025-05-23T16:00:56.000000Z",
  "tested_at": "2025-06-05T12:29:52.000000Z"
}
FabienArr's avatar

@Glukinho I appreciate your helpfull, but I tried to do that, like I wrote, it doesn't work in new Laravel 12 for the model User, it work for another model.

Glukinho's avatar

@FabienArr It does work for me specifically on User model, maybe you have something else in your model? Can you post the whole App\Models\User.php file?

FabienArr's avatar

@Glukinho Here the file :

FabienArr's avatar

@Glukinho Oh you put me on a track, if I remove the public function __construct() it's ok, it works nice. What is the relation between the casts function and the __construct ? So now, how can I solve this always keeping my constructor ?

Regards

Glukinho's avatar
Level 31

@FabienArr Ah, this explains a lot. I think you should refactor your constructor to match parent's constructor (parent is \Illuminate\Database\Eloquent\Model class, there is some magic in it's constructor, you can check inside file vendor/laravel/framework/src/Illuminate/Database/Eloquent/Model.php) and include parent::__construct(...):

 public function __construct(array $attributes = [])
    {
        parent::__construct($attributes);

        if (date('m') >= 8) { // A partir du 1er Aout année n
            $this->campagne = date('Y');
        } else { // Jusqu'au 31 juillet année n-1
            $this->campagne = date('Y') - 1;
        }
    }

Can you try it?

FabienArr's avatar

@Glukinho I say you many many thanks for help me. It works nice. I think I need more training by people like you.

Regards

Please or to participate in this conversation.