Laravel时间戳显示毫秒

rap*_*dko 11 php mysql laravel laravel-5

我需要在laravel应用程序上以高精度存储updated_at时间戳,格式为"mdY H:i:su"(包括milisseconds)

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

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

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

mal*_*hal 12

你不能,因为PHP PDO驱动程序不支持时间戳中的小数秒.解决方法是选择时间戳作为字符串,这样PDO驱动程序就不知道它确实是一个时间戳,只是通过这样做,$query->selectRaw(DB::raw("CONCAT(my_date_column) as my_date_column"))这意味着你不能对所有字段使用默认选择,因此查询变得非常痛苦.您还需要在模型上覆盖其他几个与时间戳相关的方法.

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

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

DB::statement("ALTER TABLE `$tableName` ADD COLUMN created_at TIMESTAMP(3) NULL");
Run Code Online (Sandbox Code Playgroud)

请注意,此示例适用于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的原因之一.


Zac*_*ris 6

根据Malhal 的回答,我能够在这里获取小数时间戳读数。为了方便起见,将答案粘贴到此处:

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;
    }
}
Run Code Online (Sandbox Code Playgroud)

这里发生了很多事情,因为它获取应用了范围的查询,然后在末尾添加 update_at 列的选择,这会覆盖任何先前加载的 Updated_at 列,同时 Laravel 从查询中水合模型。虽然是一个丑陋的黑客,但它第一次的效果却出奇的好。

时间戳在 Laravel内部存储为Carbon :

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

输出:

2017-04-14 22:37:47.426131
Run Code Online (Sandbox Code Playgroud)

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

\DB::statement("ALTER TABLE my_table MODIFY updated_at TIMESTAMP(6) NULL DEFAULT NULL");
Run Code Online (Sandbox Code Playgroud)

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