Как я могу установить значение по умолчанию для столбца метки времени на текущую метку времени с помощью Laravel Migrations?

Я хотел бы создать столбец временной метки со значением по умолчанию CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, используя Laravel Schema Builder / Migrations. Я просматривал документацию Laravel несколько раз и не понимаю, как сделать это по умолчанию для столбца отметок времени.

Функция timestamps() устанавливает значения по умолчанию 0000-00-00 00:00 для обоих столбцов, которые она создает.


person JoeyD473    schedule 05.08.2013    source источник


Ответы (11)


Учитывая, что это необработанное выражение, вы должны использовать DB::raw(), чтобы установить CURRENT_TIMESTAMP в качестве значения по умолчанию для столбца:

$table->timestamp('created_at')->default(DB::raw('CURRENT_TIMESTAMP'));

Это безупречно работает с каждым драйвером базы данных.

Начиная с Laravel 5.1.25 (см. PR 10962 и commit 15c487fe) теперь вы можете использовать новый метод модификатора столбца useCurrent() для достижения того же значения по умолчанию для столбца:

$table->timestamp('created_at')->useCurrent();

Возвращаясь к вопросу, в MySQL вы также можете использовать предложения от ON UPDATE до DB::raw():

$table->timestamp('updated_at')->default(DB::raw('CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP'));

Опять же, начиная с Laravel 8.36.0 (см. PR 36817) теперь вы можете использовать новый useCurrentOnUpdate() метод модификатора столбца вместе с модификатором useCurrent() для достижения того же значения по умолчанию для столбца:

$table->timestamp('updated_at')->useCurrent()->useCurrentOnUpdate();

Попался

  • MySQL

    Начиная с MySQL 5.7, 0000-00-00 00:00:00 больше не считается действительной датой. Как указано в руководстве по обновлению Laravel 5.2, все столбцы временных меток должны получить допустимое значение по умолчанию при вставке записей в базу данных. Вы можете использовать модификатор столбца useCurrent() (из Laravel 5.1.25 и выше) в своих миграциях, чтобы по умолчанию столбцы меток времени соответствовали текущим меткам времени, или вы можете сделать метки времени nullable(), чтобы разрешить нулевые значения.

  • PostgreSQL и Laravel 4.x

    В версиях Laravel 4.x драйвер PostgreSQL использовал точность базы данных по умолчанию для хранения значений временных меток. При использовании функции CURRENT_TIMESTAMP в столбце с точностью по умолчанию PostgreSQL генерирует метку времени с более высокой доступной точностью, таким образом, генерируя метку времени с дробной второй частью - см. Эту скрипту SQL.

    Это приведет к тому, что Carbon не сможет проанализировать временную метку, поскольку он не будет ожидать сохранения микросекунд. Чтобы избежать этого неожиданного поведения, нарушающего работу вашего приложения, вы должны явно указать нулевую точность функции CURRENT_TIMESTAMP, как показано ниже:

      $table->timestamp('created_at')->default(DB::raw('CURRENT_TIMESTAMP(0)'));
    

    Начиная с Laravel 5.0, timestamp() столбцов были изменены, чтобы использовать точность по умолчанию, равную нулю, что позволяет избежать этого.

Спасибо @andrewhl за указание на проблему Laravel 4.x в комментариях.

Спасибо @ChanakaKarunarathne за то, что добавили новый ярлык useCurrentOnUpdate() в комментарии.

person Paulo Freitas    schedule 29.12.2013
comment
Лучшее предложение, чем мое. Используйте это вместо моего DB::statement примера, это намного проще. - person Marwelln; 01.01.2014
comment
Можно ли это также использовать для операторов PARTITION BY в ваших тестах? - person Glenn Plas; 02.01.2014
comment
Не безупречно. Для PostgreSQL CURRENT_TIMESTAMP возвращает что-то в формате: 2014-08-11 15: 06: 29.692439. Это приводит к сбою метода Carbon :: createFromFormat ('Y-m-d H: i: s', $ timestamp) (он не может проанализировать конечные миллисекунды). Это используется Laravel при доступе к отметкам времени. Чтобы исправить PostgreSQL, используйте: DB :: raw ('now () :: timestamp (0)') (ссылка: postgresql.org/docs/8.1/static/) - person andrewhl; 12.08.2014
comment
@andrewhl На самом деле я ответил только за MySQL, так как это тема вопроса. Но спасибо, что поделились этим с нами, я обновлю свой ответ, чтобы покрыть это! :) - person Paulo Freitas; 13.08.2014
comment
для сценария update_at теперь вы можете использовать '- ›useCurrent () -› useCurrentOnUpdate ()' вместо CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP - person Chanaka Karunarathne; 24.06.2021
comment
@ChanakaKarunarathne Спасибо за обновление, я только что обновил ответ, чтобы включить его! :) - person Paulo Freitas; 26.06.2021

Чтобы создать столбцы created_at и updated_at:

$t->timestamp('created_at')->default(DB::raw('CURRENT_TIMESTAMP'));
$t->timestamp('updated_at')->default(DB::raw('CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP'));

Вам понадобится версия MySQL> = 5.6.5, чтобы иметь несколько столбцов с CURRENT_TIMESTAMP

person Brian Adams    schedule 06.01.2014
comment
Почему бы просто не использовать $table->timestamps()->default(DB::raw('CURRENT_TIMESTAMP'));? - person dave; 30.06.2015
comment
@dave Потому что тогда updated_at не изменится, когда запись была изменена после ее первоначального создания - person Erik Berkun-Drevnig; 07.10.2015
comment
Да, добавить к этому timestamps () в любом случае не разрешает значения по умолчанию, так что это вообще не сработает. У меня есть код, разрешающий это, но менеджеры Laravel на самом деле не хотят, чтобы люди использовали по умолчанию то, как мы его используем (при условии, что версии MySQL до 5.6.5 не позволяют использовать несколько столбцов с метками времени по умолчанию). - person dave; 09.10.2015
comment
Фактически, updated_at управляется Eloquent, поэтому нет необходимости в бите при обновлении, поскольку он будет установлен при автоматическом обновлении модели. - person dmyers; 28.04.2016
comment
@dmyers Если вы используете красноречие, вы можете просто сделать $t->timestamps();, но это не отвечает на вопрос. - person Brian Adams; 28.04.2016

Начиная с Laravel 5.1.26, помеченного 02.12.2015, добавлен модификатор useCurrent():

Schema::table('users', function ($table) {
    $table->timestamp('created')->useCurrent();
});

PR 10962 (за которым следует commit 15c487fe) привели к этому добавлению.

Вы также можете прочитать проблемы 3602 и 11518, которые представляют интерес.

По сути, MySQL 5.7 (с конфигурацией по умолчанию) требует, чтобы вы определяли либо значение по умолчанию, либо значение NULL для полей времени.

person Gras Double    schedule 08.12.2015

Как дополнительная возможность для будущих гуглеров

Я считаю более полезным иметь null в столбце updated_at, когда запись была создана, но никогда не изменялась. Это уменьшает размер базы данных (хорошо, совсем немного), и с первого взгляда можно увидеть, что данные никогда не были изменены.

На данный момент я использую:

$table->timestamp('created_at')->useCurrent();
$table->timestamp('updated_at')->default(DB::raw('NULL ON UPDATE CURRENT_TIMESTAMP'))->nullable();

(В Laravel 7 с mysql 8).

person ndberg    schedule 23.03.2020
comment
Мне очень нравится эта идея. В некоторых случаях было бы чрезвычайно полезно иметь updates_at = null в неизмененных записях. - person atorscho; 15.09.2020
comment
лучшее, что когда-либо было, более соответствует обновленному имени - person Abraham Putra Prakasa; 06.05.2021

Вместо этого используйте предложение Пауло Фрейтаса.


Пока Laravel не исправит это, вы можете выполнить стандартный запрос к базе данных после выполнения Schema::create.

    Schema::create("users", function($table){
        $table->increments('id');
        $table->string('email', 255);
        $table->string('given_name', 100);
        $table->string('family_name', 100);
        $table->timestamp('joined');
        $table->enum('gender', ['male', 'female', 'unisex'])->default('unisex');
        $table->string('timezone', 30)->default('UTC');
        $table->text('about');
    });
    DB::statement("ALTER TABLE ".DB::getTablePrefix()."users CHANGE joined joined TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL");

Для меня это творило чудеса.

person Marwelln    schedule 24.08.2013
comment
Хороший трюк. Я хочу, чтобы построитель схем поддерживал секционированные таблицы, поскольку я использую их повсюду. Я попытался покопаться в коде, но для меня не так очевидно, где это изменить. - person Glenn Plas; 15.09.2013

В laravel 7 для установки текущего времени используйте следующее:

$table->timestamp('column_name')->useCurrent();
person user311086    schedule 27.11.2020

Если вы хотите установить текущую дату и время для столбца dateTime (например, когда я искал в Google), используйте этот способ

$table->dateTime('signed_when')->useCurrent();
person Samuel Aiala Ferreira    schedule 09.10.2020

Я использую следующую настройку в Laravel, чтобы:

  1. По умолчанию created_at для текущей отметки времени
  2. Обновить метку времени при обновлении записи

Сначала я создам файл helpers.php в корне Laravel и вставлю следующее:

<?php

if (!function_exists('database_driver')) {
    function database_driver(): string
    {
        $connection = config('database.default');
        return config('database.connections.' . $connection . '.driver');
    }
}

if (!function_exists('is_database_driver')) {
    function is_database_driver(string $driver): bool
    {
        return $driver === database_driver();
    }
}

В composer.json я вставлю следующее в autoload. Это позволяет композитору автоматически открывать helpers.php.

    "autoload": {
        "files": [
            "app/Services/Uploads/Processors/processor_functions.php",
            "app/helpers.php"
        ]
    },

В своих моделях Laravel я использую следующее.

        if (is_database_driver('sqlite')) {
            $table->timestamps();
        } else {
            $table->timestamp('created_at')->default(\DB::raw('CURRENT_TIMESTAMP'));
            $table->timestamp('updated_at')
                ->default(DB::raw('CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP'));
        }

Это позволяет моей команде продолжать использовать sqlite для модульных тестов. ON UPDATE CURRENT_TIMESTAMP - это ярлык MySQL, который недоступен в sqlite.

person Dream Ideation    schedule 12.02.2021

Вот как вы это делаете, я это проверил, и он работает на моем Laravel 4.2.

$table->timestamp('created_at')->default(DB::raw('CURRENT_TIMESTAMP'));

Надеюсь это поможет.

person Jawad    schedule 01.04.2015


person    schedule
comment
Большой. Отличный материал. Мне это тоже помогло. - person Glenn Plas; 28.05.2014
comment
небольшое замечание, прежде чем кричать: это не работает для меня в laravel, взгляните на дату написания этого ответа: 2013. Тогда он был действителен. Я был бы признателен, прежде чем вы нажмете стрелку вниз. - person Glenn Plas; 03.05.2018