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

Adjust Datetime Format to UTC in Laravel 6 Without Changing the Default Framework Timezone: Asia/Shanghai

The data inserted into the table is in UTC time, as expected

1. In the previous implementation option 1, within the database migration file, $table->timestamps(); is equivalent to nullable created_at and updated_at TIMESTAMP columns.

PHP

        Schema::create($tableName, function (Blueprint $table) {
            $table->bigIncrements('id');
            $table->timestamps();
        });

2. In the model file, $timestamps is not set and defaults to true. Eloquent automatically manages these two columns: created_at and updated_at.

3. The final generated value matches UTC+8 because the current timezone is set to UTC+8. Printing config(‘app.timezone’) yields the value: “Asia/Shanghai”. See Figure 1.

The final generated value matches UTC+8 because the current timezone is set to UTC+8. Printing config('app.timezone') yields the value: "Asia/Shanghai"
Figure 1

4. In the previous implementation option 2, the database migration file remains unchanged, but in the model file, the $timestamps property is set to false. Then, when inserting a record, it is directly defined as: now()->utc()->timestamp. The now function creates a new Illuminate\Support\Carbon instance for the current time. Its value is 8 hours ahead of UTC+8 time. See Figure 2.

In the previous implementation option 2, the database migration file remains unchanged, but in the model file, the $timestamps property is set to false. Then, when inserting a record, it is directly defined as: now()->utc()->timestamp. The now function creates a new Illuminate\Support\Carbon instance for the current time. Its value is 8 hours ahead of UTC+8 time.
Figure 2

5. I finally decided to define a mutator, which will be called automatically when we try to set the created_at and updated_at attribute values on the model. The mutator takes the value that has already been set for the attribute, allowing you to modify it and set its value onto the $attributes property inside the Eloquent model.

PHP

    /**
     * 设置创建时间
     *
     * @param $value
     * @return void
     */
    public function setCreatedAtAttribute($value)
    {
        $this->attributes['created_at'] = $this->transTz($value);
    }

    /**
     * 设置更新时间
     *
     * @param $value
     * @return void
     */
    public function setUpdatedAtAttribute($value)
    {
        $this->attributes['updated_at'] = $this->transTz($value);
    }

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

6. The data inserted into the table is in UTC time, as expected. See Figure 3.

The data inserted into the table is in UTC time, as expected
Figure 3

7. However, when using the push() method, the datetime is still: “Asia/Shanghai”. A total of 3 SQL queries are executed; the first 2 use UTC, and the 3rd uses Asia/Shanghai. See Figure 4.

However, when using the push() method, the datetime is still: "Asia/Shanghai". A total of 3 SQL queries are executed; the first 2 use UTC, and the 3rd uses Asia/Shanghai
Figure 4
PHP

$this->themeInstallationTask->themeInstallation->processing = ThemeInstallation::PROCESSING_FALSE;
$this->themeInstallationTask->themeInstallation->processing_failed = ThemeInstallation::PROCESSING_FAILED_FALSE;

$this->themeInstallationTask->themeInstallationVersionPreset->processing = ThemeInstallationVersionPreset::PROCESSING_FALSE;
$this->themeInstallationTask->themeInstallationVersionPreset->processing_failed = ThemeInstallationVersionPreset::PROCESSING_FAILED_FALSE;

$this->themeInstallationTask->processing = ThemeInstallationTask::PROCESSING_FALSE;
$this->themeInstallationTask->processing_failed = ThemeInstallationTask::PROCESSING_FAILED_FALSE;

$this->themeInstallationTask->push();

SQL

update
  `theme_installation_task`
set
  `processing` = 0,
  `theme_installation_task`.`updated_at` = '2022-06-21 10:02:50'
where
  `id` = 18;

update
  `theme_installation`
set
  `processing` = 0,
  `theme_installation`.`updated_at` = '2022-06-21 02:02:50'
where
  `id` = 18;

update
  `theme_installation_version_preset`
set
  `processing` = 0,
  `theme_installation_version_preset`.`updated_at` = '2022-06-21 02:02:50'
where
  `id` = 18;

8. The reason should be that $value is not an instance of Carbon, so $value is returned as is. We need to convert $value to a Carbon instance.

PHP

/**
     * 转换时区
     *
     * @param $value
     * @return string
     */
    private function transTz($value = null): string
    {
        if (is_null($value)) {
            return now()->utc()->toDateTimeString();
        }
        return ($value instanceof Carbon) ? $value->utc()->toDateTimeString() : Carbon::parse($value, 'utc')->toDateTimeString();
    }

9. When using the push() method, the datetime is now in UTC. This meets expectations. See Figure 5.

10. However, when using the update() method, the datetime is still: “Asia/Shanghai”.

PHP

ThemeInstallation::where('wp_theme_id', '<>', $id)->update(['role' => ThemeInstallation::ROLE_UNPUBLISHED]);

SQL

update
  `theme_installation`
set
  `role` = 'unpublished',
  `theme_installation`.`updated_at` = '2022-06-21 13:38:36'
where
  `wp_theme_id` <> 195

11. I decided to manually specify updated_at during the update. This meets expectations.

PHP

ThemeInstallation::where('wp_theme_id', '<>', $id)->update(['role' => ThemeInstallation::ROLE_UNPUBLISHED, 'updated_at' => now()->utc()->toDateTimeString()]);

SQL

update
  `theme_installation`
set
  `role` = 'unpublished',
  `theme_installation`.`updated_at` = '2022-06-21 07:39:46'
where
  `wp_theme_id` <> 195

关于作者 · 持续学习与技术实践

我是一名拥有 15 年以上开发经验的技术从业者,自 2013 年起持续运营个人技术博客,记录工作与个人项目中遇到的真实问题,以及解决问题过程中的探索、实践和思考。

除了技术写作,我也在持续开发和维护自己的独立项目,探索新技术和新工具在实际场景中的应用。我始终相信,没有不值得去解决的问题,也没有不值得去学习的技术。

如果这篇文章对你有所帮助,欢迎浏览博客中的其他文章,也欢迎交流技术经验与想法。

关于我  ·  GitHub  ·  邮件联系