90

Is it possible to update a user without touching the timestamps?

I don't want to disable the timestamps completly..

grtz

Jannick Vandaele
  • 963
  • 1
  • 7
  • 9
  • 1
    There's no method to override timestamps by default. I'm not sure, but have you tried DB::raw($yourRawQuery)? – Arda Sep 19 '13 at 21:11

10 Answers10

189

Disable it temporarily:

$user = User::find(1);
$user->timestamps = false;
$user->age = 72;
$user->save();

You can optionally re-enable them after saving.

This is a Laravel 4 and 5 only feature and does not apply to Laravel 3.

Vucko
  • 7,371
  • 2
  • 27
  • 45
Antonio Carlos Ribeiro
  • 86,191
  • 22
  • 213
  • 204
  • I've run into problems with this...? Doesn't work when set in the base model. Anyone else have an issue? – wnajar Dec 23 '13 at 13:47
  • Can you explain at all any more? Still can't get this to work and seems stupid. Also using Laravel 3. – wnajar Apr 08 '14 at 21:28
  • It's basically disabling `timestamp` before saving, in Laravel 3 the property is static, so I'm not sure if you can or not change it in runtime, look at the code: https://github.com/laravel/laravel/blob/3.0/laravel/database/eloquent/model.php#L71 – Antonio Carlos Ribeiro Apr 08 '14 at 21:49
  • 6
    This is the only solution that has worked for me. I had tried to do the more "elegant" way : `$something->save(['timestamps'=>false]);` and it just ignored it. Thanks a lot man! – Vucko Jul 26 '16 at 12:37
  • 2
    this still causes relationships to update if the model has "touches" defined. – NiRR Oct 10 '17 at 14:47
30

In Laravel 5.2, you can set the public field $timestamps to false like this:

$user->timestamps = false;
$user->name = 'new name';
$user->save();

Or you can pass the options as a parameter of the save() function :

$user->name = 'new name';
$user->save(['timestamps' => false]);

For a deeper understanding of how it works, you can have a look at the class \Illuminate\Database\Eloquent\Model, in the method performUpdate(Builder $query, array $options = []) :

protected function performUpdate(Builder $query, array $options = [])
    // [...]

    // First we need to create a fresh query instance and touch the creation and
    // update timestamp on the model which are maintained by us for developer
    // convenience. Then we will just continue saving the model instances.
    if ($this->timestamps && Arr::get($options, 'timestamps', true)) {
        $this->updateTimestamps();
    }

    // [...]

The timestamps fields are updated only if the public property timestamps equals true or Arr::get($options, 'timestamps', true) returns true (which it does by default if the $options array does not contain the key timestamps).

As soon as one of these two returns false, the timestamps fields are not updated.

Mike
  • 533
  • 5
  • 4
  • 17
    Note that this functionality is broken in Laravel 5.1 and 5.2, and has therefore been *removed* from Laravel 5.3. See: https://github.com/laravel/framework/issues/10028 – hackel Dec 07 '16 at 23:45
  • It does not work in laravel 8 – Yevgeniy Afanasyev Dec 03 '21 at 00:17
  • 1
    Not tested, but it seems possible in Laravel 8 to set the property of the model `$timestamps` to FALSE before calling the update() method. – Mike Dec 10 '21 at 04:13
  • 1
    Setting `$user->timestamps = false;` works for me in Laravel 8. Only the option of the save method has been removed. – dyedwiper Jun 06 '22 at 09:59
23

Above samples works cool, but only for single object (only one row per time).

This is easy way how to temporarily disable timestamps if you want to update whole collection.

class Order extends Model
{

 ....

    public function scopeWithoutTimestamps()
    {
        $this->timestamps = false;
        return $this;
    }

}

Now you can simply call something like this:

Order::withoutTimestamps()->leftJoin('customer_products','customer_products.order_id','=','orders.order_id')->update(array('orders.customer_product_id' => \DB::raw('customer_products.id')));
miho
  • 11,765
  • 7
  • 42
  • 85
19

To add to Antonio Carlos Ribeiro's answer

If your code requires timestamps de-activation more than 50% of the time - maybe you should disable the auto update and manually access it.

In eloquent when you extend the eloquent model you can disable timestamp by putting

UPDATE

public $timestamps = false;

inside your model.

Jurgen
  • 411
  • 10
  • 22
azngunit81
  • 1,574
  • 2
  • 20
  • 38
19

If you need to update single model queries:

$product->timestamps = false;
$product->save();

or

$product->save(['timestamps' => false]);

If you need to update multiple model queries use

DB::table('products')->...->update(...)

instead of

Product::...->update(...)
Luca C.
  • 11,714
  • 1
  • 86
  • 77
  • 1
    Everyone's calling it "model" when they mean "instance". A model is not an actual instance, it's just the class/definition that isn't an actual real object. This is a widespread falsehood, sadly. – GeneC Sep 01 '21 at 17:19
  • @GeneC We could say he's not updating instances either, he's updating the database, usually rows (specially in the second example when he "updates multiple models"). – Parziphal Nov 03 '22 at 05:18
15

For Laravel 5.x users who are trying to perform a Model::update() call, to make it work you can use

Model::where('example', $data)
     ->update([
       'firstValue' => $newValue,
       'updatedAt' => \DB::raw('updatedAt')
     ]);

As the Model::update function does not take a second argument anymore. ref: laravel 5.0 api

Tested and working on version 5.2.

hilnius
  • 2,165
  • 2
  • 19
  • 30
  • this is really helpful in Laravel 5.8 when i do multiple records update in one go and i don't want to touch the default process of updated_at functionality. – Mithilesh Jha May 22 '20 at 06:39
  • This is very clever actually, and works on most versions on Laravel. I even tried on 4.2 and it works! – Arda Mar 07 '22 at 11:10
6

I ran into the situation of needing to do a mass update that involves a join, so updated_at was causing duplicate column conflicts. I fixed it with this code without needing a scope:

$query->where(function (\Illuminate\Database\Eloquent\Builder $query) {
    $query->getModel()->timestamps = false;
})
Zane
  • 4,652
  • 1
  • 29
  • 26
4

For Larvel 5.1, you can also use this syntax:

Model::where('Y', 'X')
    ->update(['Y' => 'Z'], ['timestamps' => false]);
Marek Skiba
  • 2,124
  • 1
  • 28
  • 31
3

Laravel 9 and above

Taken directly from the documentation.

If you would like to perform model operations without the model having its updated_at timestamp modified, you may operate on the model within a closure given to the withoutTimestamps method:

Model::withoutTimestamps(fn () => $post->increment(['reads']));

So in OP's case, the code will be something like this:

User::withoutTimestamps(function () {
    $user = User::find(1);
    $user->name = 'John';
    $user->save();
});
Christhofer Natalius
  • 2,727
  • 2
  • 30
  • 39
-1

Laravel 8

Doing some overrides using seeders and on one test I have:

$item = Equipment::where('name', item_name))->first();
$item->description = 'some description';
$item->save(['timestamps' => false]);

Which works fine, but if I use firstOrNew then the $item->save(['timestamps' => false]); does not work.

// This does not work on Seeder file
$item = Model::firstOrNew(['name' => 'item_name']);
$item->description = 'some description';
$item->save(['timestamps' => false]);

// Doing the following works tho
$item = Model::firstOrNew(['name' => 'item_name']);
$item->description = 'some description';
$item->timestamps = false;
$item->save();

So in some cases you would use one over the other... Just check with die and dump to see whether +timestamps: false

$item->timestamps = false;
$item->save();

or

$item->save(['timestamps' => false]);

Edit: In my project I opted using $item->timestamps = false; so I would recommend using this as well. Here is a working snippet from laravelplayground: https://laravelplayground.com/#/snippets/4ae950f2-d057-4fdc-a982-34aa7c9fee15

Check the HasTimestamps on Laravel api: https://laravel.com/api/8.x/Illuminate/Database/Eloquent/Concerns/HasTimestamps.html

and the save method on Model: https://laravel.com/api/8.x/Illuminate/Database/Eloquent/Model.html

The save method still accepts options but passing timestamps will not work.

Dale Ryan
  • 473
  • 4
  • 9
  • Does not work... – Gass Sep 18 '21 at 16:05
  • @Gass can you tell me which one did you tried and didn't work in your case. There are cases where you should use `$item->timestamps = false;` over `$item->save(['timestamps' => false]);`. One of the method I mentioned should work. – Dale Ryan Sep 20 '21 at 01:56
  • yes, that's exactly what happened `$item->save(['timestamps' => false]);` did not work on my Laravel 8 app – Gass Sep 20 '21 at 07:05
  • @Gass for laravel 8 `$item->timestamps = false;` would work as I mentioned on the post. I simulated a code snippet on laravel playground here: https://laravelplayground.com/#/snippets/63bb8098-8fe8-43bf-9e74-3d320f82c6f9 – Dale Ryan Sep 21 '21 at 01:30