Querying a date column with Laravel's query builder - php

When writing a query against a table with a date column using the Laravel query builder, what data type should be used? The following should return 13 results but instead returns nothing:
$date = new \DateTime("-2 days");
Model::whereDate($date)->get();
Dumping the query shows that laravel is trying this:
array(3) {
'query' =>
string(62) "select * from `table` where `date` = ?"
'bindings' =>
array(1) {
[0] =>
class DateTime#310 (3) {
public $date =>
string(19) "2013-10-07 14:39:11"
public $timezone_type =>
int(3)
public $timezone =>
string(3) "UTC"
}
}
'time' =>
double(5.55)
}
Writing the query as Model::whereDate($date->format("Y-m-d"))->get() instead works but doesn't seem like the Laravel way to do it.
Is there a specific object type I should be passing into the query to filter by a date column?
EDIT: The model in this example looks like this:
class Model extends Eloquent {
protected $table = 'table';
public function getDates() {
return array('date');
}
}
The table it refers to looks like this:
CREATE TABLE table(
some_field VARCHAR(255),
date DATE
) ENGINE = 'InnoDB';
Laravel thinks the date column is a string: Model::lists('date') returns an array of strings, as does DB::table('table')->lists('date').
Changing $date = new \DateTime("-2 days"); to $date = \Carbon\Carbon::now()->subDays(2) doesn't allow me to query the date column directly with the Carbon object.
UPDATED: For whatever reason, the built-in MySQL date to \Carbon\Carbon isn't working for me, so the simplest solution was to write one as a query scope:
public function scopeDate($query, \Carbon\Carbon $date) {
return $query->whereDate($date->toDateString());
}

You should add your column in the getDates() array. By doing this Eloquent will automatically convert your datetime to Carbon object.
From the docs:
By default, Eloquent will convert the created_at, updated_at, and
deleted_at columns to instances of Carbon, which provides an
assortment of helpful methods, and extends the native PHP DateTime
class.
See this:
http://laravel.com/docs/eloquent#date-mutators
Again, providing the date in the right format (Y-m-d) may still be necessary because it is not always possible to tell how to interpret a given date

As told here, Laravel uses Carbon as a DateTime class, you can perform it using:
Model::whereDate( \Carbon\Carbon::now()->subDays(2) )->get();

Related

how to get specific date result in laravel?

example i am passing this date in $date = 2020-12-28 15:15:53
and
in db approve_date = 2020-12-28 15:15:00
i am trying to get all the record of date only like this 2020-12-28
so i tried
public function getdatedInvoice($date)
{
$invoices = Invoice::where('user_id' , Auth::id())->where('is_approved' , 1)->whereDate('approve_date' , $date)->get();
dd($invoices);
return view('approved_invoices', compact('invoices'));
}
but when i try to use whereDate it gives me nothing how i can get that data according to date?
First of all, by default, Laravel will only process the approve_date column from your database as a string, even if you set it as a date_time column.
To make Laravel process it as a real date instead, you need to add this to the top of your Invoice model:
class Invoice extends Model {
protected $dates = [
'approve_date'
];
}
Now you will be able to make date comparisons without getting weird errors.
To make your date formatted the way you want, you can go about it in 2 ways.
You can either set a default date formats on every date column in your model by adding this also to the model:
protected $dateFormat = 'Y-m-d';
https://laravel.com/docs/5.2/eloquent-mutators#date-mutators
You can also do this at runtime in your view: {{ \Carbon\Carbon::parse($invoice->approve_date)->format('Y-m-d') }}
'approve_date' is not a variable... you are missing the $ sign. It should be something like this:
$invoices = Invoice::where('user_id' ,
Auth::id())->where('is_approved' , 1)->whereDate('$approve_date' ,
$date)->get();
that variable is not being declared in the function;
After all that, you have your date like date/time and you should convert the format using (for example) Carbon https://carbon.nesbot.com/docs/

Extending DB facade Laravel

I would like to convert a timestamp and have some other values related to it. My question is how I can introduce my own method like DB::raw() that appends everything to the current select values.
So, for instance, for something like this
$user = DB::table('users')
->select('*', DB::timestamp('timestamp_column', 'convert_timezone', 'called_as'))
->where('id', 1)->first();
Let's assume that I am trying to get the value for created_at column and it's called as converted_created_at and it should return something like below.
{
id: 1,
name:'John Doe',
converted_created_at: {
'utc_time': 'created_at value as that is in utc by default',
'converted_time': 'timestamp converted into user timezone',
'diff': '10 hours ago' // difference between created_at and current timestamp
}
}
So, how do I introduce my own method that does this?
You can take example of any SQL database as you wish.
I know I can do that with Model but I wanted to see how to approach this problem using a facade.
Thank you in advance for your help.
First look here: https://stackoverflow.com/a/40615078/860099 - Try this Extend DB facade:
namespace App\Facades;
use Illuminate\Support\Facades\DB as DBBase;
class DB extends DBBase {...}
and in config/app.php change
'DB' => Illuminate\Support\Facades\DB::class,
to
'DB' => App\Facades\DB::class,`
(i write code from head)
Alternative:
You can easily create helper class eg. DBTools witch static methods and inside that methods you will use DB and construct proper query. And use it like that DBTools::yourMethod(...)
As argument to that method you can give... QUERY here is example of calling this method
DBTools::yourMethod(User::query())->first();
and inside you can easyily manipulate that query and return updated version.
ALTERNATIVE: If your goal is to add some new filed in Model (json) that not exist in db but is generated then you can use $appends (look: mutators and appends)
class User extends Model
{
protected $appends = ['converted_created_at'];
...
public function getConvertedCreatedAtAttribute() {
return ...; // return generated value from other fields/sources
}
Thanks to #kamil for showing me the way.
I am writing an answer in case anyone in the future finds this helpful.
I have come up with my own method that helps to convert timezone easily without writing too much code inside select query for DB facade for PostgreSQL.
I have created a file like this now.
<?php
namespace App\Custom\Facade;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\DB;
class DBTools extends DB
{
/**
* Convert a timestamp
* #param $timestamp - timestamp to be converted
* #param bool $insideRaw - if this helper method is getting used inside DB::raw() method
* #param null $timezone
* #param null $format - time format
* #param null $calledAs - column to called as
* #return \Illuminate\Database\Query\Expression|string
*/
public static function convertTime($timestamp, $insideRaw = false, $timezone = null, $format = null, $calledAs = null)
{
if (Auth::check()) {
if (!$timezone)
$timezone = Auth::user()->timezone;
if (!$format)
$format = Auth::user()->time_format;
}
$query = "to_char($timestamp at time zone '$timezone', '$format')" . ($calledAs ? " as $calledAs" : '');
if (!$insideRaw) {
return DB::raw($query);
}
return $query;
}
}
Now this can be easily be called inside select for DB facade or inside DB::raw() in case you're handling much more complicated query.
Hope this helps someone.

Laravel mutate date before saving to database?

I have a date that's being selected in a datepicker in the following format
Y-m-d g:i A
So using AM/PM, it shows the following in my input field, which is correct
When I submit the form offcourse Laravel won't update the record because the format is unknown to my DATETIME field in mysql.
My 'date' field is added to the $dates array so it should be parsed by Laravel
I tried using a Mutator on my Model as following, without success
public function setDateAttribute($value)
{
$this->attributes['date'] = Carbon::createFromFormat('Y-m-d g:i A', $value)->format('Y-m-d H:i:s');
}
The original value is not being updated.
Any idea what I might be doing wrong?
Thank you
Take a look at Laravel's date mutators, this handles the accessing and mutating dates going into and out of the database for you much like it does with created_at and the other default dates.
Basically, you need to add the date field to the $dates array on your model like so:
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class User extends Model
{
/**
* The attributes that should be mutated to dates.
*
* #var array
*/
protected $dates = [
'created_at', // Add if you're using timestamps on the model
'updated_at', // Add if you're using timestamps on the model
'deleted_at', // Add if you're using softDeletes on the model
'date'
];
}
This way when the model is persisted to the database it's done so as a DATETIME, whereas when it is being read from the database into your model it will be a Carbon instance
It seems that your carbon function is ok. But why it does not work, don't understand. But I have solution using PHP date function.
public function setDateAttribute($value)
{
$this->attributes['date'] = date("Y-m-d H:i:s", strtotime($value);
}
Laravel's date mutator expects a format like 'Y-m-d H:i:s', but you can use the $dateFormat attribute on your model to specify a different format. E.g.:
protected $dateFormat = 'Y-m-d g:i A';
Check out the Date Formats section in the docs under Date Mutators
Alternatively, you can parse the date using Carbon outside of the model, because attributes listed in the $dates will also accept Carbon instances:
$model->date = Carbon::createFromFormat('Y-m-d g:i A', '2016-11-29 02:00 PM');
This is the approach I typically use. To me this feels more like a front-end concern where you're trying to map a user-friendly format to one your models/DB expects, so I'll usually put this logic into a controller.

laravel 5 format datetime

I have an array that return the following date time:
$item['created_at'] => "2015-10-28 19:18:44"
And I need this outuput:
"2016-08-10T13:15:00.000+10:00"
Exist any function to convert this date?
Try this:
$dt = new \DateTime('2015-10-28 19:18:44', new \DateTimeZone('Europe/London'));
dd($dt->format('c')); // string '2015-10-28T19:18:44+00:00' (length=25)
Alternatively take a look at Carbon
You can use Laravel's accessors to get "reformatted" created_at.
public function getCreatedAtAttribute($value)
{
//Since Laravel uses Carbon you can do.
return $value->format('c');
}
This way anytime you do something like $model->created_at it will return modified created_at.
If you want to change datetime format for created_at in your database as well, you can use mutators.
More information you can find on the Laravel's docs page.

Validate Date and Time in the Laravel Model

I have a datepicker plugin to pop-up a calendar view to allow users to select a date + time, however the format which it produces is:
May 9, 2016 8:30 AM
When storing to the database, I need the format to be:
2016-09-05 08:30:00
In the controller of my application, I have:
public function save(Request $request)
{
Entry::create($request->all());
return redirect('entries');
}
Which saves the users form input, however it doesn't save the datetime due to the incorrect format. I have tried creating a new function to format the date before entering it into the database.
public function formatDate($data)
{
$returnDate = DateTime::createFromFormat('Y-d-m G:i:s', $data);
return $returnDate->format('Y-d-m G:i:s');
}
However when I call the function from the save function, it says undefined function. Am I doing something wrong or what would be the correct way to achieve this?
You have to set the correct format for DateTime::createFromFormat(). Create from format means, you have to tell a pattern to match any information in the given date. For your date, the pattern is:
DateTime::createFromFormat('F j, Y g:i A', $data);
Here is a demo: https://eval.in/567629
A list of all format options: http://php.net/manual/en/function.date.php
Both functions are inside the model?
If so, how are you trying to call the formatDate function?
You could use an anonymous function instead, try:
$formatted_date = function() use ($data) {
$returnDate = DateTime::createFromFormat('Y-d-m G:i:s', $data);
return $returnDate->format('Y-d-m G:i:s');
};
Inside your controller or model.
In Laravel, the created_at and updated_at are casted to Carbon objects
https://laravel.com/docs/5.2/eloquent-mutators#date-mutators
With your date, you could do the same thing
class User extends Model
{
/**
* The attributes that should be mutated to dates.
*
* #var array
*/
protected $dates = ['created_at', 'updated_at', 'your_date'];
}
then, when saving the date, it will be cast to the correct format.
Give that a try and let us know how you get on!
For example;
$data = "May 9, 2016 8:30 AM";
return date('Y-d-m H:i:s',strtotime($data));

Categories