Filling a model date attribute with an ISO8601 string causes a carbon exception: Unexpected data found. Trailing data
The problem is the asDateTime()
function on HasAttributes
trait. Note that it checks the following situations:
This is a issue, since ISO8601 is the standard for javascript dates for example, and also handles timezone.
IMO, before the last check, we should check if it's an ISO8601 string, otherwise I'm unable to do
MyModel::create($request->all());
forcing me to always parse de date manually into a carbon instance, and that's a pain!
some_date_field
and add it to $dates
property.some_date_field
with an ISO8601 string, eg: 2018-05-04T16:04Z
You'll get the following error:
"message": "Unexpected data found.\nTrailing data",
"exception": "InvalidArgumentException",
"file": "/var/www/vendor/nesbot/carbon/src/Carbon/Carbon.php",
"line": 836,
You can use a mutator:
public function setSomeDateFieldAttribute($value)
{
$this->attributes['some_date_field'] = Carbon::parse($value)->toDateTimeString();
}
But the "date" mutator already is a mutator! It just dont work for the most common date pattern in the world! I really hate when issues are closed without argumentation @tillkruss
Your question was answered. Using an Accessor and a Mutator solves your case.
Also, you didn't seem to have read the issue template, this is not the right place for feature requests.
most common date pattern in the world
I would argue about that ;-)
You can also specify a custom format:
protected $dateFormat = 'Y-m-d\TH:i\Z';
@staudenmeir It really will make the ISO8601 format be accepted, but it will try to save it as ISO8601 on database, and mysql doesn't accept it.
This property determines how date attributes are stored in the database, as well as their format when the model is serialized to an array or JSON
@tillkruss It really can be solved with a custom mutator, but it's just an workaround IMO. Also this isn't a feature request, it's a bug report.
Feel free to submit a PR 馃憤馃徎
I don't think the Database Driver & Version is irrelevant. Depending on the mysql strict mode settings you can either pass ISO8601 timestamps into mysql and it'll save as a UTC date time automatically, or it will fail. I have had similar issues with timestamp formats with laravel and carbon formatting and casts since I can remember, and it always requires some extra work to convert into the proper format, especially with mysql strict mode. Using the mutators is a solid solution as @staudenmeir suggested.
The strange is that I remember to do store the dates as 8601 with the date mutator without problems, but not sure if thats true.
I'll look about mysql supporting 8601, if it does I really can change the date time format to 8601 without problem!
Thanks for the idea!
I'm really agains using the mutator pattern in this case since it's the defaul behavior for a entire project, so it will be very repetitive. I'll make some testings and write down here to help anyone with same problem.
Other way around actually. Mysql stores Date Time fields in UTC without any timezone offsets. Everything you store in the timestamp fields should be converted to UTC, and you'd have to store the offsets separately for conversion on retrieval. My point was without mysql strict mode on, mysql let you pass an ISO8601 formatted timestamp and it would just save it as date time without complaining.
If this is the default behavior for the entire project, you can create a parent class for your models and override HasAttributes::asDateTime()
etc.
Most helpful comment
You can use a mutator: