Временные метки Laravel для отображения миллисекунд

Мне нужно хранить update_at timestamp с высокой точностью в приложении laravel, используя формат «mdY H: i: su» (включая milisseconds)

Согласно документации laravel, я могу настроить формат даты, установив свойство $ dateFormat в классе, но …

Основная проблема заключается в том, что построитель схем Laravel добавляет столбец типа timestamp в базу данных, когда я использую $ table-> nullableTimestamps (). И согласно документации mysql, столбцы типа TIMESTAMP допускают точность до нескольких секунд.

Любые идеи о том, как я могу это достичь?

Вы не можете, потому что драйвер PDO PHP не поддерживает дробные секунды в метках времени. Работа вокруг заключается в том, чтобы выбрать временную метку как строку вместо этого, чтобы драйвер PDO не знал его действительно $query->selectRaw(DB::raw("CONCAT(my_date_column) as my_date_column")) метку, просто выполнив $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 'Ymd H:i:s.u'; } // override to include micro seconds in the created Carbon. public function freshTimestamp() { $microtime = microtime(true); $milliseconds = sprintf("%03d", ($microtime - floor($microtime)) * 1000); return date('Ymd H:i:s.'. $milliseconds, $microtime).""; } 

Наконец, в вашей миграции, а не в nullableTimestamps, вне обратного вызова Schema выполните:

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

Обратите внимание, что этот пример был для трех знаков после запятой, но вы можете иметь до 6, если хотите, путем изменения 3 на 6 в двух местах, в таблице alter и в 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.

Основываясь на ответе Малхала , я смог получить дробную метку, чтобы работать здесь . Вставка ответа здесь для удобства:

 class BaseModel extends Model { protected $dateFormat = 'Ymd\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 увлажняет модель из запроса. Для того, чтобы быть уродливым взломом, он работал на удивление хорошо в первый раз.

Временные метки хранятся внутри Carbon в Laravel:

 dd(MyModel->first()->updated_at->format('Ymd 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() схемы миграции для этого.