Laravel Carbon does not consider timezone DST - php

Given my UsersTableSeeder.php class, I am seeding my database with fake data, using a loop:
$numberOfUsers = 150;
DB::table('users')->delete();
$faker = Faker::create();
for ($i = 1; $i <= $numberOfUsers; $i++) {
DB::table('users')->insert([
'id' => $i,
'firstName' => $faker->firstName,
'lastName' => $faker->lastName,
'email' => $faker->email,
'password' => bcrypt("123"),
'created_at' => Carbon::now()->addDays((-5 * $i) - 2)->format('Y-m-d H:i:s'),
'updated_at' => Carbon::now()->addDays(-5 * $i)->format('Y-m-d H:i:s'),
]);
}
The problem here is that when my datetime values are generated, there is a chance it might fall in a DST zone, like between 2017-03-12 02:00:00 and 2017-03-12 02:59:59 (which does happen) and it gives me the following error:
[PDOException]
SQLSTATE[22007]: Invalid datetime format: 1292 Incorrect datetime value: '2016-03-13 02:08:11' for column 'created_at' at row 1
Now I understand that I cannot put such a value in my database, because my database is smart enough to know that this zone in time doesn't exactly exit. But is there any way I can 'make' Carbon smart enough to consider DST ? I do not want to manually check it with something like:
if ($my_date > 2017-03-12 02:00:00 && $my_date < 2017-03-12 02:59:59)

In Fact Carbon can handle DST zones.
$date = '2017-03-26 02:01:01';
$date = \Carbon\Carbon::parse($date, 'Europe/Berlin');
dd((string)$date);
Results in
// an extra hour was added automatically
"2017-03-26 03:01:01"
Per default Laravel uses 'UTC' for all date and datetime operations (including Carbon). This value can be set in app/config.php
If you actually want to your datetimes be considered in 'UTC' in database a dirty workaround could be something like that:
EDIT:
// calculate current offset to UTC:
$offset = \Carbon\Carbon::now('America/Montreal')->offsetHours;
'created_at' => Carbon::now('America/Montreal')->addHours(-4 + $i)->addDays((-1 * $i) - 2)->tz('UTC')->addHours($offset)->format('Y-m-d H:i:s')

You can generate your timestamps with Carbon and provide the timezone. Try just:
Carbon::now()->format('c')

Related

Correct epoch to DateTime conversion

Whit this code:
$epoch= '1609455600';
$date = new DateTime( '#'.$epoch);
echo $date-> format( 'Y-m-d');
I see this result 2020-12-31. The server timezone is reported as Europe/Zurich (with date_default_timezone_get). But in this time zone that date should be 2021-1-1.
What is going on here?
In addition to the comment from #tuckbros. The output with var_export shows that the DateTime object has the time zone 00:00 (UTC).
date_default_timezone_set('Europe/Zurich');
$epoch= '1609455600';
$date = new DateTime( '#'.$epoch);
var_export($date);
/*
DateTime::__set_state(array(
'date' => '2020-12-31 23:00:00.000000',
'timezone_type' => 1,
'timezone' => '+00:00',
))
*/
The clean way to get the local time is to transfer the object to the desired time zone (and not to add any offset times).
$date->setTimeZone(new DateTimeZone(date_default_timezone_get()));
var_export($date);
/*
DateTime::__set_state(array(
'date' => '2021-01-01 00:00:00.000000',
'timezone_type' => 3,
'timezone' => 'Europe/Zurich',
))
*/
You can now continue to work with the DateTime object, since it has the correct time zone in addition to the correct local time.

updateOrCreate does not match Carbon date

I am using Laravel Framework 6.16.0 and I am creating from a string a date object so that I can input it in my db:
$transaction_date = Carbon::createFromFormat('Y-m-d', $tradeDate);
$filling_Date = Carbon::createFromFormat('Y-m-d H:i:s', $fillingDate, 'UTC');
$product = Product::updateOrCreate(
[
'price' => trim($price),
'qty' => $qty,
'companies_id' => $company->id,
'persons_id' => $person->id,
'amount_range' => $owned,
'filling_date' => $filling_Date,
'transaction_date' => $transaction_date,
],
[]
);
When running the above query my product does not get found as $filling_Date and $transaction_date are not matched in the database, even if my product already exists.
I am guessing, the reason is that I am creating a "new" Carbon object.
Any suggestions how to match the filling_date and transaction_date in the database?
I appreciate your replies!
Try this when converting a string to a date with Carbon
$date = Carbon::parse($yourStringDate);

MongoDb equivalence of DATE(FROM_UNIXTIME( <<VALUE>>)) and TIME(FROM_UNIXTIME( <<VALUE>>))

I have a query with timestamps stored as unix times (with milliseconds) and UTC query parameters
My SQL query would be like
select *
from my_table
where parameter1 = 'Goofy'
and DATE(FROM_UNIXTIME(time)) >= '2020-05-13 00:00:00.000 0000' --startdate
and DATE(FROM_UNIXTIME(time)) <= '2020-05-15 00:00:00.000 0000' --enddate
and TIME(FROM_UNIXTIME(time)) >= '01-01-1970 12:22:00.000 0000' --starttime
and TIME(FROM_UNIXTIME(time)) <= '01-01-1970 19:33:00.000 0000' --endtime
In Mongo (php API) my query would look like
$query = [
'$and' => [
['parameter1' => 'Goofy']
,['time' => [$gte => <conversion to unixtime for date '2020-05-13 00:00:00.000 0000' >]]
,['time' => [$lte => <conversion to unixtime for date '2020-05-15 00:00:00.000 0000' >]]
,['time' => [$gte => <conversion to unixtime for time '01-01-1970 12:22:00.000 0000' >]]
,['time' => [$lte => <conversion to unixtime for time '01-01-1970 19:33:00.000 0000' >]]
]
];
$cursor = (new MongoDB\Client())->selectCollection('myDb', 'myTable')->find($query,[]);
It looks a bit strange to separate Date and Time value, usually you use just a DateTime value which contain both, date and time part.
Anyway, converting Unix time to Date value is very simple. Just be aware, Unix time is Seconds since 1970-01-01 00:00:00Z whereas JavaScript/MongoDB uses Milliseconds since 1970-01-01 00:00:00Z
Your question is not really clear, it might be this one:
'time' => [$gte => new Date("2020-05-15 12:22:00")]
Otherwise converting a Date/Time value into integer should be done on php natively.

MySQL query for dates with CakePHP

I'm trying to select the values that fall between 2 dates, so I'll have to use <= and >=, however, my query is seemingly behaving as just less than or greater than and not considering values equal to the date.
I'm using CakePHP which saves dates in "Y-m-d h:i:a" format. I wanted to find dates on given week intervals (starting on Sundays), so I used the following.
$start_date = date('Y/m/d', strtotime('last Sunday', strtotime($timestamp)));
$formatted_start_date = str_replace("/","-",$start_date);
I tried to do find $start_date formatted as "Y-m-d" but then it wouldn't find the correct date, so I switched it to the way it is and used str_replace to format it to using "-" instead of "/".
$date_query = $this->Order->query("select * from orders where id = '$id' and created => '$formatted_start_date' and created <= '$current_timestamp' ");
Considering the time values in my database are in "Y-m-d h:i:a" format, can I use "Y-m-d" for date comparison? Is it possible to do a MySQL query that involves both LIKE and <= ?
No need to do a str_replace() - just get the Y-m-d:
$start_date = date('Y-m-d', strtotime('last Sunday', strtotime($timestamp)));
Then, instead of manually creating a query, use the CakePHP conventions (yes, you can use Y-m-d for date comparison even though the datetimes stored in the database are Y-m-d H:i:s)
$this->Order->find('all', array(
'conditions' => array(
'id' => $id,
'created >=' => $start_date,
'created <=' => $end_date . ' 23:59:59',
'my_field LIKE' => '%whatever%'
));
Though - this seems kind of strange - usually you're either looking for something by 'id' OR by a date range - not both. But - maybe you have a reason :)
And as you can see above, yes, you can add a 'LIKE' also if you need.
Above answer is totally correct, but you can take easier approach using cakePHP time helper, which has function daysAsSql, it transcribes and time-readable strings into database range.
http://book.cakephp.org/2.0/en/core-libraries/helpers/time.html#TimeHelper::daysAsSql
Just add condition's array like this.
$resl = $this->DBNAME->find('all',array(conditions=>array('date1>date','date1<date')));
Replace 'date' with your date.
This is worked for me.
Try this in your controller
$searchTutorQuery = $this->Tutordetails->find('all', array(
'conditions' => array(
"User.zip" => $zipcode1,
"Tutordetails.user_id"=>$uid,
"Tutordetails.subject_id" => $subjectName,
"Tutordetails.hourly_rate >=" => $hourly_rate
),
//"User.id =" => $userid,
'fields' => array('user_id', 'Tutordetails.subject_id', 'Tutordetails.hourly_rate',
'User.zip', 'Tutordetails.zip'),
'order' => array('Tutordetails.id DESC')
));

PHP date() function inserting zeros into database

I have an array like so which has the column names of the table on the left and the associating values on the right.
$proceduredata = array
(
'patient_id' => $patientfk,
'name_id' => $procedurenamefk,
'department_id' => $departmentfk,
'dosage_id' => $dosagefk,
'edocument' => NULL, //not implemented yet
'user_id' => $this->session->userdata('userID'),
'duration' => NULL, //not implemented yet
'submitted' => date('d-m-Y H:i:s', now()),
'comment' => NULL, //to be implemented
);
This array is then passed into a SQL insert function. The insert works fine but my "Submitted" column is getting values of this only:
0000-00-00 00:00:00
I made sure the time formats are matching? Is there something I have missed thanks.
change the date format
submitted' => date('Y-m-d H:i:s', now())
I believe that the "now()" function is a sql function and you are using PHP with the "date()" funciton. Try changing "now()" to "time()" which will give you a proper unix timestamp that the "date()" function can use to create a properly formatted date.
EDIT: I just realized I am not familiar with codeignighter, so please excuse me if the "now()" function is part of that framework.
now() is not a function, change now() to time(). Alternatively, date()'s second paramater is optional if you omit it date automatically uses the current date/time:
echo date('d-m-Y H:i:s');
will echo the current date/time in the format requested.

Categories