laravel model attribute updated_at show wrong format - laravel

when i print the updated_at field into the views, it returns something like this:
{ "date": "2017-12-08 15:07:26.000000", "timezone_type": 3, "timezone": "Australia/Melbourne" }
why this field behave like this?
i check the model and i explicitly cast the field to carbon (expiry_date was there before and it's a correct format):
protected $dates = [
'expiry_date',
'updated_at',
];
but the issue still persists.
do you have idea on how to solve this problem?

try setting the date format on your model.
protected $dateFormat = 'Y-m-d H:i:s';

If you echo, or do something else to either implicitly or explicitly call the __toString() method, you'll get the plain date.
The format that you're showing, however, is what you see when you json_encode() a Carbon object.
Make sure that whatever you're doing to display your data is not using json_encode() on the date.

Related

Wrong timezone with Eloquent Model timestamps on $model->get(), but correct with print_r()

I am experiencing something quite weird for any Eloquent Model with Laravel 7!
P.S.: I've run on every test I did:
php artisan optimize:clear
I don't know what I am missing here!
I won't post any code because that's a simple CRUD with Model Bindings.
When saving the created_at and updated_at fields, it is correctly saved in the MySQL with my timezome "America/Sao_Paulo".
But if I do this in any controler:
return $model->get()
or
return $model->paginate()
or
Model::all()
I get the response:
{
"data": [
{
... other fields
"created_at": "2020-08-23T15:22:41.000000Z",
"updated_at": "2020-08-23T15:22:41.000000Z"
}
]
}
And it returns the wrong time with +1 hour.
However, here is where things get weird... if I print_r() any of them, I get the corret time!
Array
(
... other fields
[created_at] => 2020-08-23 12:22:41
[updated_at] => 2020-08-23 12:22:41
)
I tried to use:
public function getDateFormat()
{
return 'Y-m-d H:i:s';
}
But no effect!
Thanks in Advance!
Laravel 7 uses a new date serialization format when using the toArray or toJson method on Eloquent models with UTC
Before Laravel 7, dates would be serialized to a format like the following :
2019-12-02 20:01:00
Dates serialized using the ISO-8601 format will appear like :
2019-12-02T20:01:00.283041Z
Please note that ISO-8601 dates are always expressed in UTC.
If you would like to keep using the previous behavior you can override the serializeDate() method on your model :
use DateTimeInterface;
protected function serializeDate(DateTimeInterface $date)
{
return $date->format('Y-m-d H:i:s');
}
See the official upgrade doc here
If you have changed the timezone config in config/app.php but saving the date in the database with other timezone formats then keep the timezone to UTC so laravel doesn't change it to other formats when calling it from model class, or you can do the opposite by saving it by UTC format in database then change the config to a timezone that your app needs.
// config/app.php
'timezone' => 'UTC',

Time format of database field, help needed

Time is stored in my database as H:i:s format for a timefield.
When I query I want time returned as hours:minutes without the seconds part.
I tried to set the "protected $dateFormat " setting using a Mutator. Can anyone show an example of the dateFormat setting needed? The database must remain hour:minute:seconds time settings, only the retrieved value needs to be changed for display.
protected $dateFormat = 'Y-m-d H:i:s'; // ?
One way to solve it is to treat dates as Carbon instances. The format to save on database will be auto-converted and you should use in any format.
protected $dates = [
'field_name'
];
https://laravel.com/docs/5.8/eloquent-mutators#date-mutators
// converting db column name time_match into the function as getTimeMatchAttribute worked for me.
public function getTimeMatchAttribute($value){
return date('H:i',strtotime($value));
}
you can make it with getters function in your model
like this:
public function getTimeAttribute($time){
return date('h:i',strtotime($time))
}
Time in function name should be your column name in upper case

Laravel custom attribute not being mutated to Carbon date

I'm having problems getting Laravel to cast a custom attribute as a Carbon date. Here's an example model:
class Organisation extends Model
{
protected $dates = [
'my_date'
];
public function getMyDateAttribute()
{
return "2018-01-01 00:00:00";
}
}
I'd expect my_date to be cast to a Carbon date however if I do dd($organisation->my_date) it just returns the date as a string.
I've seen people suggest to just return a Carbon instance from the custom attribute, and this partially works, the my_date attribute is availabe as a Carbon instance within the application, however if you then return the model as Json you end up with:
{
"name": "Big Business",
"my_date": {
"date": "2018-01-01 00:00:00.000000",
"timezone_type": 3,
"timezone": "Europe/London"
}
}
Instead of the desired:
{
"name": "Big Business",
"my_date": "2018-01-01 00:00:00"
}
Has anyone else come across this and if so have you found a solution?
Update
Upon further investigation I've tracked down the problem (but I don't have a solution yet). When you return an Eloquent model the __toString magic method which runs the toJson method and as you trace down the chain it serializes any Carbon dates in the $dates variable. It also completely skips over this serialization for mutated attributes, which is what I'm seeing.
I need to find a way to seralize mutated attributes that return a Carbon date when __toString is called.
edit your Organization model to this:
use Carbon\Carbon;
class Organisation extends Model
{
public function getMyDateAttribute($value)
{
//you can manipulate the date here:
$date = Carbon::parse($value,config('timezone'));
return $date;
}
}
You if your model represents a table, you can change the data type to timestamp and laravel will put that attribute into a carbon object.
Once the attribute is a carbon object, you can change the format in the blade view.
{{ $organisation->mydate->format('Y-m-d') }}
If either cannot change the data type, or you need to a default format different from a timestamp you can use the 'cast' eloquent model property.
class Organisation extends Model{
protected $cast = [
'mydate'=>'datetime:Y-m-d H:i:s'
];
}
Casting the attribute effectively works the same as an accessor that wraps the date value with a carbon object. This is much cleaner way to write it, however.
As far as timezone is concerned, you should look to change that in the config/app.php file.
Here is the documentation.... https://laravel.com/docs/5.8/eloquent-mutators#attribute-casting

Laravel 5 how to modify default Date accessors?

I have a code like this:
public function getUpdatedAtAttribute($value) {
setlocale(LC_TIME, config('app.locale'));
return Carbon::parse($value)->formatLocalized(__('DateFormat'));
}
I want to run this accessor for each field specified in $dates array instead of manually specifying it for each date field in each model, just like default Carbon instance convertion works. How could I do this? And is there better ways of specifying default locale-dependant date format for Carbon?
I think you can use $dateFormat variable of a model to apply a common date format on all the model fields:
class Flight extends Model
{
/**
* The storage format of the model's date columns.
*
* #var string
*/
protected $dateFormat = 'U';
}
More info: https://laravel.com/docs/5.4/eloquent-mutators#date-mutators
Found an elegant and simple solution: LocalizedCarbon package. It works as simply as this:
use \Laravelrus\LocalizedCarbon\Traits\LocalizedEloquentTrait;
UPD: It seems that this package actually translating only DateDiff's, but anyway I can see how it works and use that logic in my models.
UPD2: I've dig deeper and found out what there is overloaded formatLocalized method, which allows useage of non-standard "%f" parameter, which represents month name in current application locale. So I ended up with one-liner date formatting into my View instead of Model, which is more correct.

Convert timestamp to date in Laravel?

How can I return from the database all rows with a timestamp converted to a date (d-m-Y H:i), using the all() method?
It's not created_at or updated_at column, it's custom attribute, call it birthday if you wish.
timestamp columns like created_at are being parsed first. the U is simply the timestamp format. you can return your own format. for other formats see date docs.
edit: as stated in my comment, getDateFormat() is for both ways (insert, selects). your best bet would be using format inside the model. example:
public function getMyBirthdayAttribute()
{
return $this->my_birthday->format('d.m.Y');
}
use $model->my_birthday to call the attribute.
// controller
$posts = Post::all();
// within sometemplate.blade.php
#foreach($posts as $post)
my formatted date: {{ $post->my_birthday }}
#endforeach
The better way to manage dates with Laravel IMHO is to use the getDates accessor that is build into Laravel.
All you need to do is to set a method on your Model as such.
public function getDates()
{
return [
'my_birthday',
'created_at',
'updated_at',
];
}
This will return a Carbon object. Carbon is insanely awesome for manipulating dates.
It is what Laravel does by default to created_at and updated_at.
You can then do things like:
$my_birthday->diffForHumans() // 2 Days ago
$my_birthday->format('d.m.Y') // 20.02.1979
There are tons of helpers here for you. Check out the Carbon docs: https://github.com/briannesbitt/Carbon
Definitely worth learning. It might not be easy to understand for a beginner. However, I would advise you take a look and get your head around it. It will change your life - Dates can be a pain!
In this case, you need to convert the date within the query, if mysql is being used as your database then you may use a raw query like this:
// Assumed my_birthday is like 1255033470
$raw = DB::raw("date_format(from_unixtime(my_birthday),'%b %d, %Y %l:%i %p') as dob");
$result = Model::get(array('id', 'username', $raw));
You may write it within single line:
$result = Model::get(array('id', 'username', DB::raw("...")));
Just place this on your code
$post it depend on what you create
$post ->created_at->format('d.m.Y')

Resources