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

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.

Related

Laravel Carbon does not consider timezone DST

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')

How to get start date of child time frame within parent time frame

I know exact date of the beginning of the month but I need to know when first week of this month begins and this week can start outside of this month.
I can do something like - find weekday when "MONTH" starts and subtract number of days to the beginning of the "WEEK" :
$weekday = d('w', $monthStartTimeStamp);
$weekStart = $monthStartTimeStamp - strtotime('1 day', 0) * (7 - $weekday);
Question :
Is there some way to make this calculation more generic for time frames that I do not know in advance?
Possible use cases :
Given some "DATETIME" get datetime of the first "YEAR"
Given some "DATETIME" get datetime of the first "MONTH"
Given some "DATETIME" get datetime of the first "WEEK"
Given some "DATETIME" get datetime of the first "DAY"
Given some "DATETIME" get datetime of the first "HOUR"
Given some "DATETIME" get datetime of the first "MINUTE"
For date time 2016-01-10 10:30 results would be :
YEAR : 2016-01-01 00:00
MONTH : 2016-01-01 00:00
WEEK : 2016-01-04 00:00
DAY : 2016-01-10 00:00
HOUR : 2016-01-10 10:00
MINUTE : 2016-01-10 10:30
P. S. most of the questions here specify what exactly time frame is required, e.g. "How to get beginning of the year", they do not answer how to do this for ant time frame.
Here's an idea in pseudocode:
You already have the hardest case for the week
For the rest: Convert the date to a format like: YYYYMMDDHHmm, then depending on the $interval just change the right X characters to 0:
`
$int2char = array(
'YEAR' => 8,
'MONTH' => 6,
'DAY' => 4,
'HOUR' => 2,
'MINUTE' => 0
);
$interval = 'MONTH';
$str = date("YmdHi", $timestamp);
$zeros = $int2char[$interval];
$d = substring($str, 0, 12-$zeros) . substring("00000000", 0, $zeros);
$date = DateTime::createFromFormat('YmdHi', $d);
echo $date->format('Y-m-d H:i');
`

With PHP, how to retrieve items that match created month and year

I'm using this code to retrieve news items from my MongoDB:
foreach (collection("news")->find(["created"=>$time]) as $news)
Now I would like to find only those news articles with "created" unix timestamp that matches specific month of the specific year, like April 2014.
Any help would be appreciated.
Cheers.
EDIT: Thank you all for your effort, and yes, it's unix timestamp.
How did you create the Unix Timestamp? How is it represented in the document?
Are you using the MongoDate type, or are you using an integer?
If you are using the MongoDate type then you need to construct MongoDate objects and use them for your $gte and $lt conditions
$article = array(
"title" => "My first article",
"content" => "This is good news",
"published" => new MongoDate(),
"author" => "Random guy on the internet",
);
$collection->insert($article);
$start = new MongoDate(strtotime("yesterday"));
$end = new MongoDate(strtotime("tomorrow"));
$cursor = $collection->find(array("ts" => array('$gt' => $start, '$lte' => $end)));
foreach($cursor as $article) {
var_dump($article);
}
See http://www.php.net/manual/en/class.mongodate.php for more info
you'll have build your own query:
SELECT * FROM news WHERE created >= $start_date AND created <= $end_date
where:
assuming created is unix timestamp, otherwise you should skip strtotime function
// first day of april 2014
$start_date = strtotime(date('2014-04-01'));
// last day of april 2014
$end_date = strtotime(date('2014-04-t'));
You could use DateTime::createFromFormat to create your timestamps.
$begin = DateTime::createFromFormat('!Y-m', '2014-04');
$end = clone $begin;
$end->modify('next month');
echo $begin->format('Y-m-d H:i:s'). PHP_EOL; // 2014-04-01 00:00:00
echo $end->format('Y-m-d H:i:s'); // 2014-05-01 00:00:00
And build more complex condition.
collection("news")
->find(["created" => array(
'$gte' => $begin->getTimestamp(),
'$lt' => $end->getTimestamp())]);

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