Skip to content

Eloquent Model does not correctly cast "datetime" to "timestamp with time zone" when using Postgresql #57277

@mykkode

Description

@mykkode

Laravel Version

12.32.5

PHP Version

8.3.14

Database Driver & Version

PostgreSQL 16.2 on aarch64-apple-darwin21.6.0, compiled by Apple clang version 14.0.0 (clang-1400.0.29.202), 64-bit

Description

When creating a new entity of a model with a cast of type datetime or timestamp when the database field is generated with timestamptz (timestamp with time zone) Laravel does not specify the timezone in the resulting query. As a result, PostgreSQL uses the client's timezone ("PostgreSQL assumes your local time zone for any type containing only date or time." - https://www.postgresql.org/docs/current/datatype-datetime.html)

Example:
Model Article with cast 'published_at' => 'datetime'
UTC time: 2025-10-05 20:00:00
Server timezone: Europe/Bucharest (date and time: 2025-10-05 23:00:00)

Database column: $table->timestamptz('published_at')

Creating an article Article::create(['published_at' => now()]) the resulting query will be: insert into "articles" ("published_at", "updated_at", "created_at") values ('2025-10-04 20:00:00', '2025-10-04 20:00:00', '2025-10-04 20:00:00) returning "id"

Because in the query, for the column published_at, no time zone is specified, PostgreSQL uses the client's time zone (the server, in this case UTC+3), as a result in the database will be stored 2025-10-05 17:00:00 +00:00.

There is a solution, we can add $dateFormat = 'Y-m-d H:i:s P'; in the Article model.
However, I believe that the above format can be used as default (when using pgsql database connection).

If we use a string with the time zone specified on a simple timestamp column, the timezone is stripped without modifying the date:

update articles set updated_at= '2025-10-05 23:00:00 +03:00'
update articles set published_at= '2025-10-05 23:00:00 +03:00'

First query sets updated_at = 2025-10-05 23:00:00 (it simply stripped the time zone)
The second query sets published_at = 2025-10-04 20:00:00 +00:00

This is mentioned in the documentation "If a time zone is specified in the input for time without time zone, it is silently ignored In a value that has been determined to be timestamp without time zone, PostgreSQL will silently ignore any time zone indication. That is, the resulting value is derived from the date/time fields in the input string, and is not adjusted for time zone." - https://www.postgresql.org/docs/current/datatype-datetime.html

Steps To Reproduce

Schema::create('articles', function (Blueprint $table) {
            $table->id();
            $table->dateTimeTz('published_at');
            $table->timestamps();
        });
class Article extends Model
{
    protected function casts(): array
    {
        return [
            'published_at' => 'datetime',
        ];
    }
}
Article::create(['published_at' => now()])

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