【问题标题】:Laravel timestamps to show millisecondsLaravel 时间戳以显示毫秒
【发布时间】:2015-09-22 11:47:40
【问题描述】:

我需要在 laravel 应用程序上以高精度存储 updated_at 时间戳,使用格式 "m-d-Y H:i:s.u"(包括毫秒)

根据 laravel 文档,我可以通过在类上设置 $dateFormat 属性来自定义日期格式,但是...

主要问题是当我使用 $table->nullableTimestamps() 时,Laravel 的模式构建器在数据库中添加了时间戳类型的列,并且根据 mysql 文档,TIMESTAMP 类型的列只允许精确到秒..

关于如何实现这一目标的任何想法?

【问题讨论】:

  • 您尝试过使用 mutators 吗?类似this

标签: php mysql laravel laravel-5


【解决方案1】:

您不能这样做,因为 PHP PDO 驱动程序不支持时间戳中的小数秒。一种解决方法是选择时间戳作为字符串,这样 PDO 驱动程序就不会知道它的真正时间戳,只需执行 $query->selectRaw(DB::raw("CONCAT(my_date_column) as my_date_column")) 但这意味着您不能对所有字段使用默认选择,因此查询变得真实疼痛。您还需要覆盖模型上的 getDateFormat。

// override to include micro seconds when dates are put into mysql.
protected function getDateFormat()
{
    return 'Y-m-d H:i:s.u';
}

最后在你的迁移中,而不是 nullableTimestamps,在 Schema 回调之外做:

DB::statement("ALTER TABLE `$tableName` ADD COLUMN created_at TIMESTAMP(3) NULL");

请注意,此示例适用于 3 位小数,但如果您愿意,您最多可以有 6 位,方法是将 3 在两个位置更改为 6,在 alter table 和 sprintf 中,并将乘数 * 1000 调整为 1000000 6.

希望有一天 PHP PDO 会更新以解决此问题,但它已经 5 年多了,没有任何改变,所以我不抱太大希望。如果您对详细信息感兴趣,请参阅此错误报告: http://grokbase.com/t/php/php-bugs/11524dvh68/php-bug-bug-54648-new-pdo-forces-format-of-datetime-fields 我发现这个其他答案中的链接可能会帮助您更好地理解这个问题: https://stackoverflow.com/a/22990991/259521

PHP 最近确实显老了,我认为这个问题是我考虑迁移到更现代的 Node.js 的原因之一。

【讨论】:

    【解决方案2】:

    基于malhal's answer,我能够读取小数时间戳以工作here。为方便起见,在此处粘贴答案:

    class BaseModel extends Model
    {
        protected $dateFormat = 'Y-m-d\TH:i:s.u';
    
        protected function asDateTime($value)
        {
            try {
                return parent::asDateTime($value);
            } catch (\InvalidArgumentException $e) {
                return parent::asDateTime(new \DateTimeImmutable($value));
            }
        }
    
        public function newQuery()
        {
            $query = parent::newQuery();
    
            if($this->usesTimestamps()) {
                $table = $this->getTable();
                $column = $this->getDeletedAtColumn();
    
                $query->addSelect(DB::raw("concat($table.$column) as $column"));
            }
    
            return $query;
        }
    }
    

    这里发生了很多事情,因为它获取了应用范围的查询,然后在末尾添加了对 updated_at 列的选择,这会覆盖任何以前加载的 updated_at 列,而 Laravel 从查询中对模型进行水合。作为一个丑陋的 hack,它在第一次时运行得非常好。

    时间戳在 Laravel 内部存储为 Carbon

    dd(MyModel->first()->updated_at->format('Y-m-d H:i:s.u'));
    

    输出:

    2017-04-14 22:37:47.426131
    

    另外,请务必运行迁移以将您的列转换为小数时间戳。微秒精度将时间戳的大小从 4 个字节提高到 7 个字节,但这是 2017 年,当您发现自己在提供陈旧的缓存条目时,不要让通过选择毫秒精度来节省一两个字节花费您一大笔钱:

    \DB::statement("ALTER TABLE my_table MODIFY updated_at TIMESTAMP(6) NULL DEFAULT NULL");
    

    遗憾的是,我还没有找到一种方法来修改迁移架构 timestamps() 函数来执行此操作。

    【讨论】:

    • 当使用你的 newQuery 函数时,添加选择后我没有得到返回给我的完整对象。就查询而言,我觉得这里缺少一些东西
    猜你喜欢
    • 2015-04-17
    • 2019-12-09
    • 2023-03-11
    • 2011-09-06
    • 1970-01-01
    • 1970-01-01
    • 2014-08-31
    • 1970-01-01
    • 2011-08-02
    相关资源
    最近更新 更多