How does laravel/lumen dateformat 'U' actually works? - laravel

I'm not able get the timestamps with dateformat 'U' working in lumen.
In migration:
$table->timestamps();
In Model:
protected $dateFormat = 'U';
protected $dates = [
'created_at',
'updated_at',
'deleted_at'
];
public function getDateFormat()
{
return 'U';
}
Insert row from controller:
$model = new ApiKey;
$model->random= rand();
$model->name = $name;
$model->scope = $scope;
$model->save();
It does insert the row in the database but with 0000-00-00 00:00:00 values for created_at and updated_at columns.
Also, while retrieving a model via toArray or toJson it thrown exception:
I want lumen to autoupdate the timestamps and retrive timestamps as unixtimestamp format i.e. number of seconds from 1st Jan 1970.
Also, $table->timestamps() didn't create deleted_at column. What do I need to do get this column created via laravel.
Is there any other option than $table->timestamp('deleted_at');?
I've found a solution bay changing timestamps columns to int. But I want the things to be done in laravel way.

Unix timestamps are integers, not compatible with SQL datetime/timestamp fields. If you want to use unix timestamps, use integer field types for storage.
The timestamps() method only creates created_at and updated_at, soft deletes are not enabled by default. This method should not be used if you want integer storage.
If you only want to change the output format when serializing data, use casting:
/**
* The attributes that should be cast to native types.
*
* #var array
*/
protected $casts = [
'created_at' => 'datetime:U',
];

This is likely caused by the fact that Laravel/Lumen created the date/time columns as the type timestamp not int so you're trying to save wrong type of data in the field, causing the 0000-00-00 00:00:00.
This would also cause the carbon issue as you are trying to createFromFormat with the wrong format compared to the content.
You can use $table->integer('deleted_at'); in your migration to create a deleted_at column.
TL;DR:
Manually create your date time columns with $table->integer('updated_at').

<?php
namespace App\Traits;
use Illuminate\Support\Carbon;
trait sqlServerDateFormat
{
public function fromDateTime($value)
{
return Carbon::parse(parent::fromDateTime($value))->format('d-m-Y H:i:s');
}
}

Related

Right way to save timestamps to database in laravel?

As part of a standard laravel application with a vuejs and axios front-end, when I try to save an ISO8601 value to the action_at field, I get an exception.
class Thing extends Model {
protected $table = 'things';
// timestamp columns in postgres
protected $dates = ['action_at', 'created_at', 'updated_at'];
protected $fillable = ['action_at'];
}
class ThingController extends Controller {
public function store(Request $request) {
$data = $request->validate([
'action_at' => 'nullable',
]);
// throws \Carbon\Exceptions\InvalidFormatException(code: 0): Unexpected data found.
$thing = Thing::create($data);
}
}
My primary requirement is that the database saves exactly what time the client thinks it saved. If another process decides to act on the "action_at" column, it should not be a few hours off because of timezones.
I can change the laravel code or I can pick a different time format to send to Laravel. What's the correct laravel way to solve this?
The default created_at and updated_at should work fine.
You should always set your timezone in your config/app.php to UTC
Add a timezone column or whichever you prefer in your users table
Do the time-offsets in your frontend or api response
Here's a sample code to do the time offset in backend
$foo = new Foo;
$foo->created_at->setTimezone('America/Los_Angeles');
or frontend using momentjs
moment(1650037709).utcOffset(60).format('YYYY-MM-DD HH:mm')
or using moment-timezone
moment(1650037709).tz('America/Los_Angeles').format('YYYY-MM-DD HH:mm')
class Thing extends Model {
protected $table = 'things';
// timestamp columns in postgres
protected $dates = ['action_at', 'created_at', 'updated_at'];
protected $fillable = ['action_at'];
}
class ThingController extends Controller {
public function store(Request $request) {
$data = $request->validate([
'action_at' => 'nullable',
]);
// convert ISO8601 value, if not null
if ($data['action_at'] ?? null && is_string($data['action_at'])) {
// note that if the user passes something not in IS08601
// it is possible that Carbon will accept it
// but it might not be what the user expected.
$action_at = \Carbon\Carbon::parse($data['action_at'])
// default value from config files: 'UTC'
->setTimezone(config('app.timezone'));
// Postgres timestamp column format
$data['action_at'] = $action_at->format('Y-m-d H:i:s');
}
$thing = Thing::create($data);
}
}
Other tips: don't use the postgres timestamptz column if you want to use it with protected $dates, laravel doesn't know how to give it to carbon the way postgres returns the extra timezone data.
See the carbon docs for other things you can do with the $action_at instance of \Carbon\Carbon, such as making sure the date is not too far in the future or too far in the past. https://carbon.nesbot.com/docs/

laravel current timestamp in migration with carbon

I want to display created_at as a timestamp like this :
created_at : 1625501162
so this is my created_at column in migration:
$table->string('created_at')->Carbon::now()->timestamp;
Now I want this field to be created automatically when a new record is created and record the current time. so when i change the line to this :
$table->string('created_at')->useCurrent(Carbon::now()->timestamp);
gives me this error :
Method call is provided 1 parameters, but the method signature uses 0 parameters
so how can i fix this problem?
What other ways do you suggest for timestamp created_at and store it automatically?
If you want your column to be a timestamp you should use timestamp() instead of string(). useCurrent() doesn't take a parameter. Change
$table->string('created_at')->useCurrent(Carbon::now()->timestamp);
to
$table->timestamp('created_at')->useCurrent();
https://laravel.com/docs/8.x/migrations#column-method-timestamp
https://laravel.com/docs/8.x/migrations#column-modifiers
Edit: to always get a timestamp instead of a date you can use
protected $casts = ['created_at' => 'timestamp'];
in your Model.
Instead of string you may use timestamp() in your migration.
$table->timestamp('created_at')->useCurrent();
Also you may use casting inside model to always get expected format when receiving model.
class Something extends Model {
protected $cast = [
'created_at' => 'timestamp'
];
}
A simpler way is to configure the date format of the model
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Flight extends Model
{
/**
* The storage format of the model's date columns.
*
* #var string
*/
protected $dateFormat = 'U';
}
No need to put a default value in the migration. everytime created_at, updated_at and deleted_at(if you use soft delete) is to be updated/filled, it will be in a unix timestamp format
Migration should be an integer
$table->integer('created_at')->nullable(); //you can omit this nullable
$table->integer('updated_at')->nullable(); //you can omit this nullable
// if you use softDelete trait
$table->integer('deleted_at')->nullable();
This is an example of a column createdAt. When a new record is created, it defaults to the date in UNIX format.
$table->integer('createdAt')->default(DB::raw('extract(epoch from now())'));

How to input the date from YYYY-MM-DD to DD-MM-YYYY in laravel

Some people know how to change the YYYY-MM-DD format to become DD-MM-YYYY when inputting to the database and how to display it from the database.
StudentsController.php
public function store(Request $request)
{
//
$students = new Student();
$students->nis = $request->nis;
$students->nama = $request->nama;
$students->jk=$request->jk;
$students->nama_sekolah = $request->nama_sekolah;
$students->alamat_sekolah = $request->alamat_sekolah;
$students->tanggal_mulai = $request->tanggal_mulai;
$students->tanggal_selesai=$request->tanggal_selesai;
$students->email=$request->email;
$students->alamat_siswa=$request->alamat_siswa;
$students->no_hp=$request->no_hp;
$students->email_siswa=$request->email_siswa;
$students->nama_guru=$request->nama_guru;
$students->save();
return back()->with('success','Data Berhasil Ditambahkan');
}
PHP can parse most date formats automatically, so to parse either format you can just create a Datetime or Carbon with the date string as the first argument.
Laravel can then automatically transform Datetime and Carbon instances to the correct format for your database, so you can do something like:
$dateX = new Carbon($request->get('date_attr')
$students = new Student();
// other attributes
$students->date = $dateX;
$students->save();
return back()->with('success','Data Berhasil Ditambahkan');
MySQL expects date to be formatted like YYYY-MM-DD. So while saving data to the database keep it as it is. When you are displaying the date, you can format it as you wish. To do so make your date as a date in your model.
class Student extends Model
{
protected $guarded = [];
/**
* The attributes that should be mutated to dates.
*
* #var array
*/
protected $dates = ['date'];
}
Now you can format your date attribute anywhere like
$student->date->format("d-m-Y")
It will give you the date in DD-MM-YYYY format.
In Laravel 5, you can do it using carbon class.
\Carbon\Carbon::parse('2019-04-24')->format('d-m-Y');
Use the strtotime date format:
date("d-m-Y", strtotime($date));

Adding two created_at on one insert

I want to add another created_at column on the database columns for reference.
I want to have a created_at and created_at1 at the same time.
This is what I have in my Model:
const CREATED_AT = 'created_at1';
protected $dates = [created_at, created_at1];
But I'm receiving this error: Field 'created_at' doesn't have a default value.
You do not need to add casting to the created_at since Laravel has already done it for you.
You need to add inside the string like
protected $dates = ['created_at1']
If you want to set the created_at1 when a new model is created, you can add Model Events.
Inside your model,
protected static function boot(){
parent::boot();
static::creating(function($model){
$model->created_at1 = Carbon::now();
});
}
Inside controller
$model = Model::create([
...
]);
Now it will set created_at and created_at1
For the insert, you have to manually save the value to the created_at1 because it will not reflect the model event.
Model::insert([
...
'created_at1' => Carbon::now()
]);
You might not be passing value to created_at column while inserting data. Please do check. If this is not the case please do provide more information on your problem.

In laravel how do I fetch date as date instead of datetime format?

In my database some fields are set as date, while others are datetime or timestamp formats. However when fetching data, the "date" fields are also shown with the 00:00:00 time string attached at the end. How can I prevent this?
You can use date/datetime casting with an additional format parameter as described in the Eloquent: Mutators documentation.
class User extends Model
{
protected $casts = [
'created_at' => 'datetime:Y-m-d',
];
}
This will apply the given format when serializing the model to an array or json. If you want to use a different format in your blade templates, you can use the format() function on the datetime property you want to change:
{{ $user->created_at->format('Y-m-d') }} or {{ $user->created_at->toDateString() }}
You will have to add the created_at column to the $dates property of your model though:
protected $dates = [
'created_at',
];
This basically adds 'created_at' => 'datetime' to your $casts.

Resources