MySQL Date comparison advice - php

I'm setting up a script to run daily and check for members who meet a certain age - automated emails can be set up in a CMS and assigned to be sent at any age, either in months or years. To handle this via PHP and MySQL, the number of months is passed as a parameter to a method, which I deal with as below. However, I'm not sure I'm going about this in the easiest way! Partly because of the formatting of the UK date format, I'm converting from string to datetime to unix timestamp to make the comparison.
Can anyone find a better way of going about this? Thanks
// If num of months provided is a year, make calculation based on exact year
if ($age_in_months % 12 == 0)
{
// Using 365 days here (60 * 60 * 24 * 365 = 3153600)
$clause = 'WHERE ROUND((UNIX_TIMESTAMP() - UNIX_TIMESTAMP(STR_TO_DATE(dob, "%d/%m/%Y"))) / 31536000) = ' . $age_in_months;
}
else
{
// Using 30 days as avg month length (60 * 60 * 24 = 86400) - convert months to days
$clause = 'WHERE ROUND((UNIX_TIMESTAMP() - UNIX_TIMESTAMP(STR_TO_DATE(dob, "%d/%m/%Y"))) / 86400) = ' . $age_in_months * 30;
}

change that column to type date or datetime
don't use UK date format, use ISO-8601 format
and index on that column

I'd just use the MySQL date logic. You can be sneaky and use the fact that the DOB column is stored as text this lie this:
SELECT whatever FROM users WHERE dob LIKE DATE_FORMAT(CURDATE(), '%d/%m/%%');
This will take the current date, format it like a UK date (the %% turns into a single %). So for today (as I post), that would be '20/12/%'. It uses that for a LIKE on dob, giving you everyone with a birthday of '20/12/(something)'.
It's a little weird, but it actually takes advantage of having the DOB stored in a text format. I'm assuming an index on DOB, although you could get away without it if you don't have too many people.
For the second query, it looks like you're trying to do a 'People who were born 6 months ago' type thing. Is that right? You could so something like this:
SELECT whatever FROM users WHERE DATE_ADD(CURDATE(), INTERVAL -6 MONTH) = STR_TO_DATE(dob, '%d/%m/%Y');
It's not a pretty, and if you want people who were born 6, 18, 30... months ago it won't work. In that case, I'd actually go with something like what you have. It's not ideal, but it would more-or-less work and the results may be close enough for you.

datediff(now(),dob) will give you the difference in days between two dates.
If you want to see whether somebody is at least 18, try if (date_sub(now(),18 years) > dob)
Everybody born in February? if (month(dob) = 2)
See http://dev.mysql.com/doc/refman/5.1/en/date-and-time-functions.html
Edit: and since you're stuck with (for unfathomable reasons) a database showing a date that's not in date format, replace dob with your STR_TO_DATE(dob... section.

Related

How to search between two datetime in php MySQL?

I have a table called reports in MySQL(MariaDB) . There is a one(out of 5) column named logdate which is is of type datetime .columns stores the the date and time (in 24hr format) .
for ex here is sample value from that column
2021-04-10 09:35:00
I have to find all reports between a given date and time .
I get 4 variables from form data in PHP
$fromdate= $_POST['fromdate'];
$todate= $_POST['todate'];
$fromtime= $_POST['fromtime'];
$totime= $_POST['totime'];
$fromtime and $totime are just integers with value from 0-23 for hours.
For example the condition may be like get all data between 4th April 2021
from 5 o'clock To 8 April 2021 18 o'clock
i.e. From 2021-04-04 03:00:00 to 2021-04-08 18:00:00. There will be never condition on minutes and seconds .
My question is how to construct a datetime in PHP compatible with MySQL types so I can have good(efficient, there are millions of records in table ) search speed?
for ex
$select = "select * from reports where logdate between ? and ? ";
P.S: I tried saving date and time as integer as unixtime stamp. But when i convert from and to date received using strttotime() I facing time format issue due to bug in my code which so can use datetime only.
If you have any suggestion to improve efficiency of DB please suggest.Thanks
Hi this link may be of help in optimizing date comparison
MySQL SELECT WHERE datetime matches day (and not necessarily time)
This one below, will help you in formatting your strtotime() by using strptime()
https://www.php.net/manual/en/function.strptime.php
Also check your spelling or typo; you wrote "strttotime()" instead of "strtotime()" yours has an extra 't' in str"tto"time, it should be str"to"time, though without the double qoutes
Though I can't say for sure this is the most effective way but you can use hour(logdate) to compare with $fromdate and $todate
$select = "select * from reports where hour(logdate) between ? and ? ";
But it will only compare hour part. Please mention how you are getting date part to compare?
It is not a good idea to make a calculation on a field in the WHERE CLAUSE. In this case MySQL / MariaDB must calculate the value from this field to comapare it to see
if this ROW has this condition. So MySQL must read the whole table FULL TABLE SCAN and CANT use any INDEX.
A better way to do this is to store the calculation on fix site. Then MySQL calculated it only one time and can use a Index ( if there one) .
you can easy use a query like this:
$select = "SELECT * FROM reports where logdate between date(?) + INTERVAL ? HOUR AND date(?) + INTERVAL ? HOUR ";
to test see:
SELECT date('2021-04-05') + INTERVAL 16 HOUR;
result:
2021-04-05 16:00:00
Here is what is working for me after using Bernds solution .
I constructing datetime string in php
$fromstr ="$fromdate"." "."$fromtime".":00:00";
$tostr="$todate"." "."$totime".":00:00";
here is my query looks like for date of 7th April to 10th April
$ select = "SELECT * FROM reports where logdate >= '$fromstr' and logdate <= '$tostr' order by logdate";
after echoing it
"SELECT * FROM reports where logdate >= '2021-04-07 3:00:00' and logdate <= '2021-04-10 5:00:00' order by logdate";```
However I am not sure if can use index for logdate column and utilize it with above query.

How to get time difference between current date time and timestamp value in HH:MM:SS

What i want is simple, i have timestamp in my mysql database that records date and time data registers. What i want is to calculate the timediff between timestamp and current time then subtract from 3hours to know time remaining in hh:mm:ss format, please someone help out.
You should use the following part in your query:
SELECT TIME_FORMAT(SEC_TO_TIME(AVG(TIMESTAMPDIFF(SECOND, NOW(), column_with_date_to_compare))), '%H:%i')
You must skip the AVG part if you do not want averages but a result per row (or you have only one row to check) (or use GROUP BY [something])
The part 'then subtract from 3hours', I don't understand. You only want to show the records where the time is less than 3 hours? Just use WHERE TIME(record_to_check) > (NOW() - 10800).
If you want to add, calculate or do other things to influence the result, just do so before SEC_TO_TIME, you can do the math (with seconds) there.
I've interpretted your question as how to calculate the time remaining in a 3 hour period starting at a datetime stored in a DB, to be displayed in HH:MM:SS format...
I generally find it easier to manipulate dates / times in php rather than wihtin an SQL query. So my approach would be to:
read strings from the database
convert them into unix timestamps (ie
number of seconds elapsed since a given epoch)
manipulate them mathematically (ie add on 3 hours and subtract the curent time)
lastly convert the result back into a date / time in your chosen
format.
Assuming $start_str has been read from your DB
$start_str = '08-03-2017 11:10:00';
$start_ts = strtotime("$start_str");
$end_ts = $start_ts + (3 * 60 * 60);
$now_ts = strtotime('NOW');
$remaining_ts = $end_ts - $now_ts;
$remaining_str = ($remaining_ts > 0)? sprintf('%02d:%02d:%02d', ($remaining_ts/3600),($remaining_ts/60%60), $remaining_ts%60) : "None, time's up";
echo ($start_str.'|'.$start_ts.'|'.$end_ts.'|'.$now_ts.'|'.$remaining_ts.'|'.$remaining_str);
Examples...
08-03-2017 11:10:00|1488971400|1488982200|1488983863|-1663|None, time's up
08-03-2017 14:30:00|1488983400|1488994200|1488983982|10218|02:50:18
Obviously in reality you're only interested in the last field, but the others show you what you're playing with during the process.

Updating number values by year / month with php

I was wondering if there is a way to update a certain number value, per year?
Similar to how you would update a website date in the footer like this:
<?php echo date("Y"); ?>
I'm looking for a way to update a set number each year / month.
Example, say a website says they have been in business for 10 years. Then when the next year passes, I want PHP to automatically update the value to 11 years. Note, that I have to start with the number 10
Another example would be for age: John is 21. After a year passes I want PHP to update the site to say, John is 22.
Or Betty has worked here for 5 months.... After the next month passes it would update to 6, then once it hits 12 months is would change to 1 year then 2 years etc... Thats a little more involved, but you get the idea.
If someone knows how this can be achieved I would appreciate the help, or if you can point me in the right direction to solving this problem that would work too.
Yes, you need to understand two things - the current date and the date you are comparing it to. You then simply need to compare the too.
I would suggest using the PHP DateTime, DateInterval, etc. classes which greatly simply this for you.
For example:
$now = new DateTime('now');
$comparison_date = new DateTime('2005-01-01'); // roughly 10 years ago
$interval = $now->diff($comparison_date); // returns DateInterval object
$years_difference = $interval->y;
You can find your answer here:
How to calculate the difference between two dates using PHP?
By using strtotime() to convert two dates to unix time and calculate the number of seconds between them then reconvert to human readable.
To calculate the difference between to years you can use a simple sum like this:
<?php
$cur_year = date("Y");
$year = 2008;
$total_years = $cur_year - $year;
echo ($total_years);
?>
For months you could use a similar thing
Substract the initial Unix timestamp with the current timestamp (time() returns it), divide by 60 * 60 * 24 * 365, and round accordingly (you will probably want to floor() the years an user has been registered, and ceil() the years a bussiness have been working)
$start = 12345646;
$years = ceil((time() - $start) / 31536000.0); // Important: use a float
Note this uses "year" as a set of 365 days. It won't take into account leap years.

Store month and year in mysql database

I have following date:
$params['ExpirationMonth'];
$params['ExpirationYear'];
I need some suggestion regarding how can I store only month and year in mysql database. After some research I have found 3 ways to do it.
1) I can use 1st as the days and can store along with month and year.
2) Instead of using date I can use varchar datatype and can only store month and year in it.
3) I can store the two as two separate columns as integers. i.e. for month and year.
Which is the better way?. Need some suggestion. Thanks.
You can use a date column, keeping in mind that:
You could set the day portion to 1
The card is good for the entire month of the specified expiry date. 0512 means valid through 31 May 2012.
Advantages:
Sorting is straight forward (compared to storing as varchar)
Date operations are straight forward (compared to storing as varchar/two integer columns)
Data stays in one column (compared to storing as two integer columns)
Sample queries:
-- expires in 2012
WHERE expires >= '2012-01-01' AND expires < '2012-01-01' + INTERVAL 1 YEAR
-- expires in Dec 2012
WHERE expires >= '2012-12-01' AND expires < '2012-12-01' + INTERVAL 1 MONTH
1) I can use 1st as the days and can store along with month and year.
This option is better as if there is any calculation or sorting need
to be done, it will be useful and handy.
2) Instead of using date I can use varchar datatype and can only store month and year in it.
3) I can store the two as two separate columns as integers. i.e. for month and year.
For above two option are fine as it will take less space as compare to
date or timestamp. But you can do calucation or orderby with this. For
calculation you need to convert it date by "str_to_date" function
I hope this will help you in some way.
stored as UNIX. suddenly need to add something in the future, and no problem to get anything out of date
Expiration Month/Year from credit cards means that this card is valid until the end of this Month/Year.
Best way to store as a comparable date you should get the last day of this month
STR_TO_DATE( CONCAT( '01,', #Month, ',', #Year, '%d,%m,%Y )
+ INTERVAL 1 MONTH
- INTERVAL 1 DAY
You can always store it like YYYYDD as an integer:
So for May 2021 you can store this integer: 202105

Search for age in php

I am trying to build up a search function, which gets the results by an age range. The database containts the birthday of an user (e.g. 1980-09-11 00:00:00). Now I am trying to search for users e.g. by using $agefrom = 15; and $ageto = 18;.. But I do not now how the php code and the db statement should look like..
I want to make the most stuff in php and then only do a sql query like (birth < birth_to AND birth > birth_from)..
Thank you for your help!
The simplest query, which won't work with total accuracy would be
SELECT ...
FROM ...
WHERE YEAR(birthday) BETWEEN (YEAR(now()) - 18, YEAR(now()) - 15)
This will fail if a person's birthday has not yet occured in a particular year (e.g. it's May 1st, and their b-day is June 15th). Handling that case will require a bit more date math to check for "year is right but day/month is wrong".
I would think it's easiest to construct the dates you need as 15 and 18 years ago (in PHP), then place those in the query with a BETWEEN statement. Round to midnight or you'll get bad edge cases.

Categories