没有不值得去解决的问题,也没有不值得去学习的技术!

在 Laravel 6 中,在不更改框架默认时区:Asia/Shanghai 的情况下,日期时间格式调整为 UTC (二)

在有需要使用到 UTC 的模型中,引入新的 trait 文件,查看未使用新的 trait 与使用了新的 trait 的区别。相差 8 小时

1、由于程序主体的时区为:Asia/Shanghai,但是在一些模型中打算存储 UTC 的时区值

2、参考:https://www.shuijingwanwq.com/2022/07/11/6776/ ,发现仍然不符合预期。在第 7 步骤的调整后。同样的程序,在队列中运行后,字段 updated_at 的值,其对应的时区有时候仍然为:Asia/Shanghai,大部份时候的时区为:UTC。如图1

参考:https://www.shuijingwanwq.com/2022/07/11/6776/ ,发现仍然不符合预期。在第 7 步骤的调整后。同样的程序,在队列中运行后,字段 updated_at 的值,其对应的时区有时候仍然为:Asia/Shanghai,大部份时候的时区为:UTC
图1

3、暂时调整为如下实现,当 $value 为字符串时,则返回当前的 UTC 时间。

PHP

    /**
     * 转换时区
     *
     * @param $value
     * @return string
     */
    private function transTz($value = null): string
    {
        return now()->utc()->toDateTimeString();
    }

4、发现仍然存在时区为:Asia/Shanghai 的情况。不过发现时区在不断变换的模型,可能是因为在队列中不断地 save() 所导致。大概在队列中同一个模型执行了 5 次以上的 save() 方法。如图2

发现仍然存在时区为:Asia/Shanghai 的情况。不过发现时区在不断变换的模型,可能是因为在队列中不断地 save() 所导致。大概在队列中同一个模型执行了 5 次以上的 save() 方法
图2

5、最终决定采用沿用原有步骤 4 的方案。不过步骤 4 的方案不适用于 delete() 方法,其生成的 SQL 中,deleted_at 的值的时区仍然为:Asia/Shanghai。如图3

最终决定采用沿用原有步骤 4 的方案。不过步骤 4 的方案不适用于 delete() 方法,其生成的 SQL 中,deleted_at 的值的时区仍然为:Asia/Shanghai
图3
SQL

update `table` set `deleted_at` = '2023-01-12 11:19:17' where `id` = 534

6、决定仍然使用修改器,因为其在同一个队列中,同一个模型仅会执行一次 delete() 方法。

PHP

    /**
     * 设置删除时间
     *
     * @param $value
     * @return void
     */
    public function setDeletedAtAttribute($value)
    {
        $this->attributes['deleted_at'] = $value ? now()->utc()->toDateTimeString() : $value;
    }

7、最后发现生成的 SQL 不符合预期,时区仍然为:Asia/Shanghai

SQL

update `table` set `deleted_at` = '2023-01-12 16:05:00' where `id` = 531

8、由于软删除使用了 trait SoftDeletes,尝试覆写方法:runSoftDelete()

编辑前:

PHP

$time = $this->freshTimestamp();

编辑后:

PHP

$time = Date::now('UTC');

9、发现生成的 SQL 符合预期,时区为:UTC

SQL

update `table` set `deleted_at` = '2023-01-12 08:09:02' where `id` = 534

10、在有需要使用 UTC 时区的模型中,最后实现如下

PHP

use Illuminate\Database\Eloquent\SoftDeletes;

class ThemeInstallation extends Model
{
    use SoftDeletes;



    /**
     * Perform the actual delete query on this model instance.
     *
     * @return void
     */
    protected function runSoftDelete()
    {
        $query = $this->setKeysForSaveQuery($this->newModelQuery());

        $time = Date::now('UTC');

        $columns = [$this->getDeletedAtColumn() => $this->fromDateTime($time)];
        file_put_contents(storage_path() . '/logs/SoftDeletes.runSoftDelete-' . microtime(true) . '-' . mt_rand()  . '.txt', print_r($time, true), FILE_APPEND | LOCK_EX);

        $this->{$this->getDeletedAtColumn()} = $time;

        if ($this->timestamps && ! is_null($this->getUpdatedAtColumn())) {
            $this->{$this->getUpdatedAtColumn()} = $time;

            $columns[$this->getUpdatedAtColumn()] = $this->fromDateTime($time);
        }

        $query->update($columns);

        $this->syncOriginalAttributes(array_keys($columns));
    }
}

11、由于有多个模型需要用到 UTC 时区,为了避免代码冗余,新建一个 trait 文件:/app/Traits/UtcSoftDeletes.php

PHP

setKeysForSaveQuery($this->newModelQuery());

        $time = Date::now('UTC');

        $columns = [$this->getDeletedAtColumn() => $this->fromDateTime($time)];

        $this->{$this->getDeletedAtColumn()} = $time;

        if ($this->timestamps && ! is_null($this->getUpdatedAtColumn())) {
            $this->{$this->getUpdatedAtColumn()} = $time;

            $columns[$this->getUpdatedAtColumn()] = $this->fromDateTime($time);
        }

        $query->update($columns);

        $this->syncOriginalAttributes(array_keys($columns));
    }
}


12、在有需要使用到 UTC 的模型中,引入新的 trait 文件,查看未使用新的 trait 与使用了新的 trait 的区别。相差 8 小时。如图4

在有需要使用到 UTC 的模型中,引入新的 trait 文件,查看未使用新的 trait 与使用了新的 trait 的区别。相差 8 小时
图4

PHP / Laravel / Yii2 老项目维护与长期技术支持

如果你的 PHP / Laravel / Yii2 项目已经上线,但遇到原开发离职、Bug 长期无人修复、接口不稳定、性能下降、代码难以接手等问题,可以联系我做一次远程技术排查。

适合以下情况:
✅ 老旧 PHP 系统无人维护
✅ Laravel / Yii2 项目 Bug 修复
✅ 后台管理系统小功能迭代
✅ RESTful API 接口排查
✅ MySQL / Redis / Nginx 性能问题
✅ 长期远程兼职维护

可先从一次小问题开始:
✅ 线上报错排查
✅ 接口异常分析
✅ 慢查询与性能瓶颈定位
✅ 代码结构初步评估
✅ 部署环境与日志检查

如需咨询,请联系我,并注明:PHP 维护咨询

联系方式:
Telegram:@shuijingwan
微信:13980074657
邮箱:shuijingwanwq@gmail.com