Carbon unexpected date-time format in Laravel
Asked Answered
S

1

5

I have problem with Carbon and HTML5 input input[type=datetime-local] because this input sends datatime in format Y-m-d\TH:i (eg. 2016-11-20T11:45).

I have method in my controller:

public function store(ModelStoreFormRequest $request) 
{
    $model = new Model($request->all());
    $model->save();
    return redirect->action(/*...*/);
}

And I get exception:

InvalidArgumentException in Carbon.php line 582: Data Missing
1. in Carbon.php line 582
2. at Carbon::createFromFormat('Y-m-d H:i:s', '2016-11-20T11:45') in HasAttributes.php line 709

So I have solved this problem by creating next function in my model:

public function setStartedAtAttribute($startedAt)
{
    if( $startedAt instanceof Carbon ) {
        $this->attributes['started_at'] = $startedAt;
        return;
    }

    if( strpos($startedAt, 'T' ) ) {
        $this->attributes['started_at'] = Carbon::createFromFormat('Y-m-d\TH:i', $startedAt);
        return;
    }

    $this->attributes['started_at'] = Carbon::createFromFormat('Y-m-d H:i:s', $startedAt);
}

But I do not like this solution, I wonder if there are more elegant solution? I am thinking to use ModelStoreFormRequest::prepareForValidation() method and there to check if format of date is: Y-m-d\TH:i to change datetime value to format: Y-m-d H:i:s, or maybe to use Carbon::parse() method like this:

protected function prepareForValidation() 
{
    $input = $this->all();
    $input['started_at'] = \Carbon\Carbon::parse($input['started_at']);
    $this->replace($input);
}

But I still do not know is this solution fine. I am trying to separate concerns and obligation of each class... What do you suggest? Any other more elegant solution or stick to the current one?

Savory answered 2/10, 2017 at 14:58 Comment(3)
What's wrong with using new Carbon($startedAt)?Crannog
@MarkBaker That's fine, but my problem is that Laravel by default calls Carbon::createFromFormat('Y-m-d H:i:s') but what you are suggesting is to just use new carbon instead of Carbon::parse(), buy still leaves me with problem should that go into setter, FormRequest::preapreForValidation or somewhere else...Savory
File an issue at github.com/laravel/framework if Laravel cannot handle datetimes formatted according to the ISO 8601 standard out-of-the-box.Atrabilious
L
6

Instead of creating custom function for changing format or editing any base of Laravel here is the simple solution try this

$startedAt= Carbon::createFromFormat('Y-m-d\TH:i','2016-11-20T11:45');

will return you this :

2016-11-20 11:45:00

Now you as for your concern I will recommend you to use it in controller if you will not gonna need in future at multiple places.

You can also use it as an mutators in your Model if you need to store date in that format into db and will not be needed at multiple places like this

Mutators

public static $snakeAttributes = false; // because you have camel case here
public function setStartedAtAttribute($value)
{
    $this->attributes['startedAt'] = Carbon::createFromFormat('Y-m-d\TH:i',$value);;
}

Accessors

public function getStartedAtAttribute()
    {
        $startedAt = $this->attributes['startedAt'];
        return $startedAt
    }

You can create a separate trait for your function if you need to use it at multiple places which I recommend is a best practice.

trait YourTraitName{
  public function yourfunction(){
$startedAt= Carbon::createFromFormat('Y-m-d\TH:i','2016-11-20T11:45');
return $startedAt;
    }
}

Exclude middlewares, middlewares are used generally for authentication check read more about middleware here

For more Carbon related operation you can read here and test here

Leastwise answered 4/10, 2017 at 5:7 Comment(5)
I know I can use that, as you can see I am already using it, however my concern is where does that part of the code goes, should I put it as a setter in my model, in form request, middleware or somewhere else...Savory
well it depends on your need if you want to store date in that format into db you can use mutators for that middleware is not that a good choice until you use it in multiple routes. or if you are using it only once you can use it in controller itself choice is your based on your requirementLeastwise
Thank you, I guess the best place is in controllerSavory
Yeah it is ☺ happy coding pleasure to help you ☺Leastwise
exactly what i was looking for, thank youPulitzer

© 2022 - 2024 — McMap. All rights reserved.