Laravel Carbon allow trailing data at Postgresql Timestamp - laravel

I have some timestamp records on the DB that have trailing milliseconds at the timestamp and some not have. How to allowing that trailing data (millisecond) in carbon? Is this possible?
Here's the sample of my data
I can't always change the data manually because there are some other services using the same database and sometimes storing timestamp with trailing milliseconds.

As you are using Postgres, your timestamp probably has TIME WITH TIMEZONE
Example: "2018-04-19 07:01:19.929554".
In Such case have to add a date Mutator to your Model.
In your Model add this field for date mutator:
protected $dateFormat = 'Y-m-d H:i:sO';
Alternate Solution:
As you have a mix of timestamps with and without milliseconds I suggest you try this solution using Laravel field mutators:
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class User extends Model
{
/**
* Parse the created at field which can optionally have a millisecond data.
*
* #param string $created_at
* #return Carbon::Object
*/
public function getCreatedAtAttribute($created_at)
{
// Try to remove substring after last dot(.), removes milliseconds
$temp = explode('.', $created_at);
// If created_at had milliseconds the array count would be 2
if(count($temp) == 2) {
unset($temp[count($temp) - 1]); // remove the millisecond part
} else {
$temp = [$created_at]; // created_at didnt have milliseconds set it back to original
}
return Carbon::parse(implode('.', $temp))->format('Y-m-d H:i:s')
}
}

I have observed in Laravel, storing datetime in database ignores
millisecond field, probably depends on version and db server type.
Also Laravel has whereData() and whereTime() query builders but we
need something like whereDateTimeTz() in all cases.
I recommend storing datetime as unix timestamps in database.
From user timezone convert to GMT and save it to db as millis-timestamp
Carbon::parse('date', 'user_timezone')->setTimezone('GMT')->getPreciseTimestamp(3);
While displaying just convert the db timestamp (GMT) back to user timezone including DST status.

Laravel 7 provides better date parsing by falling back to Carbon::parse if the recevied timestamp from the database doesn't match the expected $dateFormat.
PR: https://github.com/laravel/framework/pull/30628

Related

Laravel - different formats for date/time query

I am learning Laravel and I have some small problem on controllers - when I use DB, the query returns date time without timezone but if I use model, the query returns full datetime.
public function test($switch)
{
//return "YYYY-MM-DDThh:mm:ss.000000Z"
if ($switch) return Position::select('id','created_at')->orderBy('id')->get();
// return "YYYY-MM-DD hh:mm:ss"
return DB::table('positions')->select('id','created_at')->orderBy('id')->get();
}
Why? What I need to dof I want "YYYY-MM-DDThh:mm:ss.000000Z" on both cases?
Thanks for solution.
thanks for advice
You should use the DB::raw
The following statement will convert the datetime value created_at from +00:00 timezone to +10:00 timezone.
You can try this
return DB::table('positions')->select(DB::raw('id',CONVERT_TZ('created_at','+00:00','+10:00'))->orderBy('id')->get();
you can set your timezone that you wants to convert it
They are the same data, probably just different classes of date and you can always format your date. Laravel utilizes Carbon date library which is excellent and should be used primarily.
If you try to print out your date class with get_class() for Eloquent Position created_at, you probably got Carbon and DB::table('positions') created_at, you probably got DateTime and that's why the value looks different (but you still got the same date).
If you want to convert your DateTime to Carbon, you can do
$newDate = new \Carbon\Carbon($position->created_at)
Thanks Anurat,
I realized this fact shortly after sending the previous question.
... but there is another 'issue' - both times are my local time - time in "YYYY-MM-DDThh:mm:ss.000000Z" is not UTC time as I expected.
I changed my function:
public function test($switch = false)
{
$data = Position::selectRaw('id, created_at, UNIX_TIMESTAMP(created_at) unix')->orderBy('id')->get();
foreach ($data as $d) {
$conv = new \DateTime($d->created_at);
$d->conv = intval($conv->format('U'));
$d->diff = $d->conv - $d->unix;
}
return $data;
}
... and result is
0
id 1
created_at "2021-03-18T12:36:59.000000Z"
unix 1616067419
conv 1616071019
diff 3600
As you see, the difference is 1 hour (as my timezone offset). Where is a problem?
Thanks.

Laravel: set timestamps from datetime to now as int

I am creating a Laravel application. Earlier I used to design the database with the datetime datatypes for created_at and updated_at, but a friend of mine suggested me that I should use timestamp instead of datetime because it's good with different timezones.
Is this a good idea to use timestamp instead of datetime format? Will there be any performance issues? If "No" then how can we change the default format of timestamps from datetime to timestamp globally in a laravel application.
For example (default):
$model->created_at = "yyyy-mm-dd h:i-s";
$model->updated_at = "yyyy-mm-dd h:i-s";
Integer timestamp:
$model->created_at = 1523246567;
$model->updated_at = 1523246567;
Unfortunately, I'm not able to answer your first two questions, but Laravel does provide an easy way to change the format your dates are stored in.
The Date Mutators documentation says that one can set the $dateFormat property on your model like this:
/**
* The storage format of the model's date columns.
*
* #var string
*/
protected $dateFormat = 'U';
The 'U' format would be "Seconds since the Unix Epoch." More formats are available in the php date documentation.
You would also need to change your model's migration. Replace $table->timestamps(); with $table->unsignedInteger('created_at'); and $table->unsignedInteger('updated_at');.
To use a specific date format "globally", i.e. for all of your models, you could either set the date format on a base model and let all of your models inherit that model, or use a trait. See this question for an example.

How to add minutes to to a date in laravel

There are few ways that I can do this using PHP but I could not find a way to do that using laravel specific way.
I have a time that is coming from database in below format: Y:M:s
ex: 05:15:00
This is what I want to do:
add 30 minutes to that date, according to above example result should be: 05:45:00
Below is my current code and I want to add 30min to $endTime:
//get database value according to selected date
$allocatedDateQuery = DB::table('appointments')->where('date', $request->date)->get();
//loop throug every record to get time
foreach ($allocatedDateQuery as $value) {
$time = $value->time;
$endTime = $time;
}
I just got a perfect solution from here.
Use Carbon extention to simply acheive that.
What you have to do is parse your time to Carbon object and then you can use addMinutes() to do that and then you can format() if you want:
foreach ($allocatedDateQuery as $value) {
$time = Carbon::parse($value->time);
$endTime = $time->addMinutes(30);
$allocateValidateMessage .= Carbon::parse($value->time)->format('H:i') . ' - ' . $endTime->format('H:i') . ' ';
}
Usually I use php's date, you can give this a try
Date("Y:M:s", strtotime("30 minutes", strtotime($value->time))
That is converting your time into a string, adding 30minutes to it and converting it to the date format of your desire
Since you said you are grabbing the date from the database I am assuming you are also using Eloquent to query from the database.
You can use Eloquent Mutator Method in your Database Modal Class to mutate the data like this:
public function getAppointmentsAttribute($value) {
return Date("Y:M:s", strtotime("30 minutes", strtotime($value->time)));
}
You can even add another attribute without mutating the original value using Attribute assignments as well. This method caches your query and reduces database calls. Since you do not need to run local loops on the record your code is much cleaner.

Laravel: Check if time + 4 hours has passed

I store in my database a date format like this:
2017-02-22 16:55:40
I added it to my database like this:
Carbon::now();
I need to check if 4 hours passed since this date.
How I can do this? I couldn't figure out how I can convert this format into Carbon or timestamp.
If you are using Laravel and the date is a Carbon instance from a Model you have access to the whole Carbon API.
You can use the Difference API of Carbon for this specific purpose.
echo $model->thedate->diffInHours($now, false);
If your model does not threat the date as a carbon instance you can cast it by adding the date to the dates array of the current model like so
protected $dates = [
'field_name',
];
Check out Date casting for more information
Update with an explicit example
$user = User::first();
// This will return the difference in hours
$user->created_at->diffInHours(Carbon\Carbon::now(), false);
You can convert it to a Carbon object with:
Carbon::parse('2017-02-22 16:55:40');

how to select one month back records from data base in laravel

how select one month back records from current date from database in laravel. I am trying this code.
This is controller code.
class LoginHistoryController extends Controller {
public function index()
{
$login_history = LoginHistory::where('login_date','BETWEEN', '(CURDATE() -
INTERVAL 10 DAY) AND CURDATE()' )->get();
}
}
but i am getting error.
I will have a approach something like this. First I will calculate the date like
$today = date('Y-m-d');
$date = date_create($today);
date_sub($date, date_interval_create_from_date_string("30 days"));
$beforeOneMonth = date_format($date, "Y-m-d");
You should have the intended value in $beforeOneMonth by now. Now you can compare it in anyway you like whether you use IN operator or >=. For eg.
$login_history = LoginHistory::where('login_date','>=', $beforeOneMonth)->get();
Give it a try. If you are storing date in some other format, you can do your own tricks to format the date and do the thing
Another way to do it would be with whereRaw:
$login_history = LoginHistory::whereRaw(
'login_date BETWEEN (CURDATE() - INTERVAL 10 DAY) AND CURDATE()'
)->get();
Note that whereRaw has the side effect of making your code less portable since you're using SQL that might be specific to your database server. But sometimes you just can't do what you would like using the query builder.

Resources