默认时区 – 永夜 https://www.shuijingwanwq.com 没有不值得去解决的问题,也没有不值得去学习的技术! Fri, 13 Jan 2023 01:36:10 +0000 zh-Hans hourly 1 https://wordpress.org/?v=7.0 在 Laravel 6 中,在不更改框架默认时区:Asia/Shanghai 的情况下,日期时间格式调整为 UTC (二) https://www.shuijingwanwq.com/2023/01/13/7345/ https://www.shuijingwanwq.com/2023/01/13/7345/#respond Fri, 13 Jan 2023 01:36:10 +0000 https://www.shuijingwanwq.com/?p=7345 浏览量: 106 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 时间。


    /**
     * 转换时区
     *
     * @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



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


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


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


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


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


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


$time = $this->freshTimestamp();


编辑后:


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


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


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


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


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
<pre class="wp-block-syntaxhighlighter-code">

<?php

namespace App\Traits;

use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Support\Facades\Date;

trait UtcSoftDeletes
{
    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)];

        $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));
    }
}


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

图4

]]>
https://www.shuijingwanwq.com/2023/01/13/7345/feed/ 0
在 Laravel 6 中,在不更改框架默认时区:Asia/Shanghai 的情况下,日期时间格式调整为 UTC https://www.shuijingwanwq.com/2022/07/11/6776/ https://www.shuijingwanwq.com/2022/07/11/6776/#respond Mon, 11 Jul 2022 01:19:35 +0000 https://www.shuijingwanwq.com/?p=6776 浏览量: 99 1、之前的实现方案一,在数据库迁移文件中。$table->timestamps(); 相当于可空的 created_at 和 updated_at TIMESTAMP。


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


2、在模型文件中,未设置 $timestamps ,默认为 true,Eloquent 自动管理这两个列:created_at 和 updated_at。 3、最终生成的值与东八区一致,因为当前时区设置为东八区。打印:config(‘app.timezone’) ,其值为:”Asia/Shanghai”。如图1
最终生成的值与东八区一致,因为当前时区设置为东八区。打印:config('app.timezone') ,其值为:"Asia/Shanghai"

图1

4、之前的实现方案二,数据库迁移文件无变化,但是模型文件中,$timestamps 属性设置为 false。然后在插入记录时,直接定义为:now()->utc()->timestamp。now 函数为当前时间创建一个新的 Illuminate\Support\Carbon 实例。其值相对于东八区时间,提前了 8 小时。如图2
之前的实现方案二,数据库迁移文件无变化,但是模型文件中,$timestamps 属性设置为 false。然后在插入记录时,直接定义为:now()->utc()->timestamp。now 函数为当前时间创建一个新的 Illuminate\Support\Carbon 实例。其值相对于东八区时间,提前了 8 小时。

图2

5、最终决定定义一个修改器,当我们尝试在模型上设置 created_at 和 updated_at 属性值时,该修改器将被自动调用。修改器会获取属性已经被设置的值,允许你修改并且将其值设置到 Eloquent 模型内部的 $attributes 属性上。


    /**
     * 设置创建时间
     *
     * @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、插入表中的数据为 UTC 时间,符合预期。如图3
插入表中的数据为 UTC 时间,符合预期

图3

7、但是,当使用 push() 方法时,日期时间仍然为:”Asia/Shanghai”。总记 3 条 SQL,前 2 条 SQL 使用 UTC ,第 3 条 SQL 使用的 Asia/Shanghai。如图4
但是,当使用 push() 方法时,日期时间仍然为:"Asia/Shanghai"。总记 3 条 SQL,前 2 条 SQL 使用 UTC ,第 3 条 SQL 使用的 Asia/Shanghai

图4



$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();




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、原因应该在于 $value 并非 Carbon 的实例,因而原样返回 $value。需要将 $value 转换为 Carbon 的实例。


/**
     * 转换时区
     *
     * @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、当使用 push() 方法时,日期时间已经为 UTC 了。符合预期。如图5 10、但是,使用 update() 方法时,日期时间仍然为:”Asia/Shanghai”
<pre class="wp-block-syntaxhighlighter-code">

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

</pre>
<pre class="wp-block-syntaxhighlighter-code">

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

</pre>
11、决定在更新时手动指定 updated_at。符合预期。
<pre class="wp-block-syntaxhighlighter-code">

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

</pre>
<pre class="wp-block-syntaxhighlighter-code">

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

</pre>
]]>
https://www.shuijingwanwq.com/2022/07/11/6776/feed/ 0