如何全局处理所有 Eloquent 时间戳包括时区

How to globally treat all Eloquent timestamps as including timezone

我有一个 Laravel 应用程序,我只是在每次迁移中切换到 timestampTztimestampsTz。一旦我 运行 php artisan migrate 我立即 运行 进入 "Trailing data" issues with Carbon 由于更改引起的日期格式不匹配。

当我无意使用无时区时间戳列时,我不想将 $dateFormat 属性 添加到我创建的每个模型中。我也不想引入一个特征或创建一个新的超类来扩展 Eloquent 的模型,然后我需要将其添加到我已经拥有的每个模型(以及我将来生成的模型)中。

有什么办法可以避免这一切,让每个时间戳字段都被视为都有时区吗?

这在 Laravel 6 中很容易完成,方法是创建一个新的 Illuminate Grammar class 并覆盖 getDateFormat 方法,如果 dateFormat 则为 used as a fallback 属性 缺少模型。

进去看看vendor/laravel/framework/src/Illuminate/Database/Query/Grammars。您的 class 将需要根据您连接到的数据库扩展此处找到的一种特定于供应商的语法 classes。对于这个例子,我将扩展 PostgresGrammar。像这样调整 app/Providers/AppServiceProvider.php

use Illuminate\Support\Facades\DB;

class AppServiceProvider extends ServiceProvider
{
    /**
     * Register any application services.
     *
     * @return void
     * @throws \Doctrine\DBAL\DBALException
     */
    public function register()
    {
        // ...

        $conn = DB::connection(DB::getDefaultConnection());
        $platform = $conn->getDoctrineConnection()->getDatabasePlatform();
        $conn->setQueryGrammar(new class($platform->getDateTimeTzFormatString()) extends PostgresGrammar {
            protected $date_format;

            public function __construct(string $date_format)
            {
                $this->date_format = $date_format;
            }

            public function getDateFormat()
            {
                return $this->date_format;
            }
        });
    }
}

这会将原始查询语法替换为另一个语法,让我们可以接管日期格式字符串。匿名 class 用于避免为这个小功能创建一个单独的文件,但您可以选择将其移动到它自己的文件中以提高可读性。匿名 class 被传递给 $platform->getDateTimeTzFormatString() 的值作为构造函数的唯一参数,然后存储该值以供 getDateFormat 方法使用。

此更改后,任何尾随数据错误都应该永远消失。只需确保在以后的每次迁移中使用 timestampTztimestampsTz。 3rd 方库通常允许您发布与它们捆绑在一起的任何迁移,允许您根据需要进行调整。