Временные метки Laravel для отображения миллисекунд
Мне нужно сохранить метку timestamp updated_at с высокой точностью в приложении laravel, используя формат "m-d-Y H: i: s.u" (включая milisseconds)
Согласно документации laravel, я могу настроить формат даты, установив свойство $dateFormat в классе, но...
Основная проблема заключается в том, что построитель схем Laravel добавляет столбец типа timestamp в базу данных, когда я использую $table- > nullableTimestamps(). И согласно документации mysql, столбцы типа TIMESTAMP разрешают только точность до нескольких секунд.
Любые идеи о том, как я могу это достичь?
Ответы
Ответ 1
Вы не можете, потому что драйвер PHP PDO не поддерживает доли секунды в метках времени. $query->selectRaw(DB::raw("CONCAT(my_date_column) as my_date_column"))
- вместо этого выбрать метку времени в виде строки, чтобы драйвер 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 в двух местах, в таблице изменения и в 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 Я нашел эту ссылку в этом другом ответе, который может помочь вам лучше понять проблему: fooobar.com/questions/412013/...
В последнее время PHP действительно показывает свой возраст, и я считаю эту проблему одной из причин, по которой стоит перейти на более современный Node.js.
Ответ 2
Основываясь на malhal answer, я смог получить дробную метку времени для работы здесь. Вставка ответа здесь для удобства:
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 увлажняет модель из запроса. Для того, чтобы быть уродливым взломом, он работал удивительно хорошо в первый раз.
Временные метки хранятся внутри Carbon в Laravel:
dd(MyModel->first()->updated_at->format('Y-m-d H:i:s.u'));
Вывод:
2017-04-14 22:37:47.426131
Также не забудьте выполнить миграцию, чтобы преобразовать ваши столбцы в дробные временные метки. Точность Microsecond повышает размер временных меток с 4 байтов до 7 байтов, но это 2017 год, не позволяйте сохранять байты или два, выбирая миллисекундную точность, стоить вам удачу позже, когда вы обнаружите, что используете устаревшие записи кэша:
\DB::statement("ALTER TABLE my_table MODIFY updated_at TIMESTAMP(6) NULL DEFAULT NULL");
К сожалению, я не нашел способ изменить функцию схемы миграции timestamps()
, чтобы сделать это.