So I currently have a request sending to a function:
$request->date
and date, in this case, is a string "2019-10-15"
The function is expecting \DateTime $scheduled as the argument this date is going to
How can I properly (using Carbon/laravel) convert this date string to dateTime in this request portion where it's being sent?
In your controller where you need the date, use this:
$date = Carbon::parse($request->date);
You can simply instantiate a DateTime from that date
$scheduled = new \DateTime($request->date);
As Laravel have no casts support inside request object, I would use passedValidation inside the custom request object:
public function rules()
{
return [
'date' => 'required|date',
];
}
protected function prepareForValidation(): void
{
$this->merge([
'date' => Carbon::parse($this->get('date'))
]);
}
public function getDate(): \DateTime
{
return $this->get('date');
}
Getter is optional, I like it just because it defines a type.
In Laravel we have a Request layer where all this stuff should be handled, controllers might get cluttered if we put casting and parsing into them.
This has not been appropriately tested.
Related
I'm looking for a DateTime Mutator that change the format of dates, I'm working with Oracle DB and the admitted Format is (DD/MM/YYYY) and the input type "date" stores dates in (YYYY,MM,DD) format.
I found the $date function and a trait by Torzer, but I have to indicate the fields that I want to convert the format.
is there some trait or function that detect all date fields and convert them automatically in a format (DD/MM/YYYY)? this without indicate the field.
nowadays I use protected $date in my model:
protected $dates = [ 'fecha_nac', 'fecha_nac1', 'fecha_nac2', ];
By default laravel uses date formate 'Y-m-d H:i:s' if you want to use a different format you can customize it in your model in the following way.
protected $dateFormat = 'your date formate';
in your case it will be.
protected $dateFormat = 'd-m-Y';
You can override the getDates method on HasAttributes trait.
/**
* Get the attributes that should be converted to dates.
*
* #return array
*/
public function getDates()
{
$defaults = [static::CREATED_AT, static::UPDATED_AT];
return $this->usesTimestamps()
? array_unique(array_merge($this->dates, $defaults))
: $this->dates;
}
On your model:
public function getDates()
{
$dates = parent::getDates();
// add your dynamic logic here
return $dates;
}
I would really go for explicitly defining which fields should be converted as these dynamic operations can be expensive if you are working with the model quite a lot.
I have my VitalSignSet model:
class VitalSignSet extends Model
{
protected $dates = [
'datetimetaken',
];
. . .
}
Now in my function I have this function which returns the json encoded encounter with the latest vital sign set. (Encounter has a hasMany relationship with VitalSignSet) Before the return though, I would like the datetimetaken field to be formatted for human readability, but just for this particular method. (which is why I did not use accessors)
public function get(Request $request, Encounter $encounter) {
// Setting the latest vital sign set
$encounter->latest_vitals = $encounter->VitalSignSets()
->orderBy('datetimetaken','desc')->get()->first();
// Formatting the date :
// Works when just returning the date.
// Does not return in this format when returning the model with the date.
$encounter->lastest_vitals->datetimetaken->format('M j, Y');
return $encounter->toJson();
}
The above method is accessed from a js ajax request. When I parse and log the response, the datetimetaken format hasn't changed. (still in YYYY-mm-dd H:i:s format) But when I return just $encounter->latest_vitals->datetimetaken; after formatting, a string is returned with the format I set. But when I return the containing VitalSignSet model $encounter->latest_vitals; (json response), the format is in YYYY-mm-dd. Why is that?
This is because you're only accessing the data object, you're not actually changing it.
Unfortunately, there is no way (that I've been able to find) to edit the format of the Carbon instance in the model. This is because Laravel uses the same format to parse the datetime from the database as it does to format it to a string.
Also, you won't be able to just assign the formatted string to the original as Eloquent will try and parse that string (and fail).
One way (if you want/need to keep the key as datetime) would be to convert the output to an array, edit the value, and then return that:
$latestVitals = $encounter->VitalSignSets()
->orderBy('datetimetaken', 'desc')->first();
$encounter->latest_vitals = collect($latestVitals->toArray())
->pipe(function ($item) use ($latestVitals) {
$item['datetimetaken'] = $latestVitals->datetimetaken->format('M j, Y');
return $item;
});
return $encounter;
If you don't mind changing the key to be something else (e.g. formatted_datetimetaken) you could add an accessor to what ever model is used for you VitalSignSet:
public function getFormattedDatetimetakenAttribute()
{
return $this->datetimetaken->format('M j, Y');
}
And then just use append() i.e.
$encounter->latest_vitals = $encounter->VitalSignSets()
->orderBy('datetimetaken','desc')
->first()->append('formatted_datetimetaken');
Finally, you could simply edit the datetime in your js with something like http://momentjs.com/docs. Assuming your response it assigned to the variable response:
response.latest_vitals.datetimetaken = moment(response.latest_vitals.datetimetaken, "YYYY-MM-DD HH:mm:ss")
.format("MMM D, YYYY")
Hope this helps!
I've built an application in Laravel and eloquent returns dates in this format: 2015-04-17 00:00:00. I'm sending one particular query to JSON so I can make a graph with D3, and I think I would like the dates in ISO8601 ('1995-12-17T03:24:00') or some other format that plays nice with the javascript Date() constructor.
Is there a way to change the date format being output to JSON on the Laravel end? I'm not sure using a mutator is the best approach because it would affect the date in other parts of my application.
Or would it be better to leave the JSON output as is, and use some javascript string methods to manipulate the date format before passing it to the Date() constructor? Which approach is more efficient?
Here is my model:
class Issue extends Model {
protected $fillable = [
'client_id',
'do',
'issue_advocate',
'service_number',
'issue_location',
'issue_description',
'level_of_service',
'outcome',
'referral_id',
'file_stale_date',
'date_closed',
'issue_note',
'staff_hours'
];
protected $dates = [
'do',
'date_closed',
'file_stale_date'
];
public function setDoAttribute($value)
{
$this->attributes['do'] = Carbon::createFromFormat('F j, Y', $value)->toDateString();
}
}
Here is my query:
$issues = Issue::with('issuetypes')
->select(['do','level_of_service','outcome','id'])
->whereBetween('do',[$lastyear,$now])
->get()->toJson();
And the JSON I get back:
[{"do":"2014-12-23 00:00:00","level_of_service":1,"outcome":1,"id":18995,"issuetypes":[{"id":9,"issuetype":"Non Liberty","pivot":{"issue_id":18995,"issuetype_id":9}}]}]
I know it's an old question, but there is still no good answer to that.
Changing protected $dateFormat will affect database, instead method serializeDate() must be overriden
class MyModel extends Eloquent {
protected function serializeDate(\DateTimeInterface $date) {
return $date->getTimestamp();
}
}
Or myself I chose to create trait
trait UnixTimestampSerializable
{
protected function serializeDate(\DateTimeInterface $date)
{
return $date->getTimestamp();
}
}
and then add
class SomeClassWithDates extends Model {
use UnixTimestampSerializable;
...
}
Expanding on umbrel's answer a bit I've created a trait that turns the DateTimeInstance into a Carbon instance so that I can easily make use of it's common formats.
In my particular case I wanted to serialize all dates according to ISO-8601.
The trait is as follows...
use DateTimeInterface;
use Carbon\Carbon;
trait Iso8601Serialization
{
/**
* Prepare a date for array / JSON serialization.
*
* #param \DateTimeInterface $date
* #return string
*/
protected function serializeDate(DateTimeInterface $date)
{
return Carbon::instance($date)->toIso8601String();
}
}
and from here I can simply use it on the relevant models...
class ApiObject extends Model
{
use Iso8601Serialization;
}
Obviously you could name the trait more appropriately if you're using a different format but the point is that you can use any of Carbon's common formats simply by replacing toIso8601String() with the format you need.
I strongly suggest you use the Carbon class to handle all your dates and datetimes variables, it already comes with Laravel 5 so you can start using whenever you want.
Check it out on Carbon Repo to see what you can do with it.
As an example, you can format dates from your model like this
Carbon::parse($model->created_at)->format('d-m-Y')
As for a good approach, I would suggest to use the Repository Pattern along with Presenters and Transformers. By using it you can define how you want your json to be displayed/mounted and opt to skip the presenter whenever you want in order to still get you Eloquent model returned when you make your queries.
use this function in any Model
protected function serializeDate(DateTimeInterface $date){
return $date->format('Y-m-d h:i:s');
}
Result
You can easily change the format that used to convert date/time to string when your models are serialized as JSON by setting $dateFormat property of your model to the format you need, e.g.:
class MyModel extends Eloquent {
protected $dateFormat = 'Y-m-d';
}
You can find docs on different placeholders you can use in the format string here: http://php.net/manual/en/datetime.createfromformat.php
If you use usuals techniques as
protected $dateFormat = 'Y-m-d';
or
protected function serializeDate(DateTimeInterface $date) { ... }
or
protected $casts = [ "myDate" => "date:Y-m-d" ];
It'll only works when laravel will serialize itself objects. And you will anyway to put those code inside all models, for all properties.
So my solution, you have to (too) put this code in all models for all date properties by at last, it works in ALL cases :
public function getMyDateAttribute()
{
return substr($this->attributes['my_date'], 0, 10);
}
I've got an entity with a duration property, declared as time type:
/* #ORM\Column(type="time") */
private $duration;
In my Symfony form, this duration property maps to a time field:
$builder->add(
'duration',
'time',
[
'input' => 'datetime',
'widget' => 'text'
]
)
As the time type does not exist in PHP, both internally use a DateTime object, so they need to add (invent) a date.
My problem is they don't appear to use the same date:
15mn extracted from the database are treated as 1970-01-01 00:15:00
15mn submitted by the form are treated as 2015-06-06 00:15:00 (i.e. today's date)
Consequence: Doctrine always consider the time has changed and always performs an SQL update.
What is the most efficient way to work around this?
i guess you could set the datetime to 1970-01-01 00:00:00 in the constructor of your entity
public function __construct()
{
$this->duration = new \DateTime('1970-01-01 00:00:00');
}
The solution lies in the setDuration() setter, as both Doctrine and Symfony use it to set the duration. Just don't update the whole DateTime object, only its time part:
public function setDuration(\DateTime $duration)
{
$this->duration->setTime(
$duration->format('G'),
$duration->format('i'),
$duration->format('s')
);
return $this;
}
Im new to PHP so apologies if this is a simple question. Please could you tell me how to auto select a date drop down in PHP (uses 3 drop downs - day/month/year). This is what my PHP code looks like:
$s = '01/08/2014 11:00:02';
$date = strtotime($s);
$objectToParse->setDateReceived(date('d/M/Y H:i:s', $date));
$form = $this->createForm(new Type(), $objectToParse);
And then the form looks like:
class Type extends AbstractType {
public function buildForm(FormBuilderInterface $builder)
{
$builder->add('dateReceived', 'date', array(
'required' => false
))
}
}
I expected a \DateTime. But at the moment I just receive a
500 Internal Server Error - TransformationFailedException error
On your class Type, add something like :
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'Acme\AcmeBundle\Entity\MyObject',
));
}
It makes the binding between the given entity (MyObject) and the form.
From Forms (The Symfony Book) : :
Every form needs to know the name of the class that holds the
underlying data (e.g. Acme\TaskBundle\Entity\Task). Usually, this is
just guessed based off of the object passed to the second argument to
createForm (i.e. $task). Later, when you begin embedding forms, this
will no longer be sufficient. So, while not always necessary, it's
generally a good idea to explicitly specify the data_class option
Also, you need to give a DateTime to the setter setDateReceived. What you gives with the datefunction is a string.
What you need to do is :
$s = '01/08/2014 11:00:02';
$date = \DateTime::createFromFormat('d/M/Y H:i:s', $s);
$objectToParse->setDateReceived($date);