Check the year of timestamps [duplicate] - php

This question already has answers here:
How to compare timestamp dates with date-only parameter in MySQL?
(11 answers)
Closed 3 years ago.
I have stored timestamps in my database. Timestamps like 483753600, 799286400, etc.
I would like to check if the year 2015 would match with any of my timestamps.
The only way that I know that I could do it, would be getting ALL the timestamps from the database and then check the year of each timestamp with getdate(799286400)['year']. That would be a solution but it's way too bad for the performance! Is there any other softer way to do this?
Update
This is what I have tried so far:
public function dateOfBirth(string $year): array {
return $query = $this->createQueryBuilder('p')
->select('p.uid')
->where("p.dateOfBirth BETWEEN :start AND :end")
->setParameter('start', "$year-01-01")
->setParameter('end', "$year-01-01")
->getQuery()
->getResult();
}
but it returns an empty array.

It looks like you are storing epoch timestamps. To check for timestamps that belong to year 2015, an efficient method would be to generate a range of epoch timestamp that represent the year boundaries, and then compare it to the stored values. Assuming that timestamps are stored in column col:
select exists (
select 1
from mytable
where col >= unix_timestamp('2015-01-01') and col < unix_timestamp('2016-01-01')
) as exists_year_2015
This query will give you a unique record, with a unique column containing a boolean value (0/1) that indicates if any record in the table has a timestamp that belongs to year 2015.
Such an expression will be able to take advantage of an index on the timestamp column.

You have a couple of problems with your code, first of all you are returning an assignment
return $query = $this->createQue...
also you set the same parameter value to both :start and :end, the string "$year-01-01" which will not match the stored timestamps, and you don't change the value of $year in between so even if it could match it would be an empty range.
You need to determine the starting and ending timestamp for the given year and use them as parameters for the query.
public function dateOfBirth(string $year): array {
// get the DateTimes
$startDate = new \DateTime("midnight January 1, $year");
$year += 1;
$endDate = new \DateTime("midnight January 1, $year");
// get the timestamps
$start = $startDate->format('U');
$end = $endDate->format('U');
return $this->createQueryBuilder('p')
->select('p.uid')
->where("p.dateOfBirth > :start")
->andWhere("p.dateOfBirth < :end")
->setParameter('start', $start)
->setParameter('end', $end)
->getQuery()
->getResult();
}

Related

Laravel query builder inject column value into Carbon query

I've got a query that I'm running in my project on a model called Domain, it returns all domains where the status column of a domain matches complete and a date column is before or equal to a specific set of days.
I've recently refactored the model columns and have included a new column called domain_alert_period which is an integer column that holds a value in days, I need to somehow target this column and put it in replace of my existing 30 so that the user is able to control the number of days prior to getting an alert.
What am I missing from this to achieve this?
return Domain::where('status', 'complete')
->where(function ($sql) {
$sql->where('domain_expires_on', '>', Carbon::now()->subDays(2)) // 2 days after expiry
->where('domain_expires_on', '<', Carbon::now()->addDays(30)); // 30 days before expiry
})
->get();
I believe you can use whereRaw() in your clause to use raw DB expressions, If its MySQL you can use DATE_ADD method with your column value for comparision
$sql->where('domain_expires_on', '>', Carbon::now()->subDays(2)) // 2 days after expiry
->whereRaw('domain_expires_on < DATE_ADD(NOW(), INTERVAL domain_alert_period DAY)');
A mysql DATE_SUB function should be used to subtract days from a domain_expires_on date. so that will be a date you should start an alert from
And then match a current date is greater or equal to that alert date
$query = $this->model
->whereRaw('CURDATE() <= DATE_ADD(`domain_expires_on` , INTERVAL 2 DAY)') // till 2 days after expiry
->whereRaw('CURDATE() >= DATE_SUB(`domain_expires_on` , INTERVAL domain_alert_period DAY)')
->get();
If i understand your question correctly what you can do is use use ($var) in your query to replace 30
$start=1; //you can also take date from user for between like `date_from` and `date_to` and parse them with Carbon insted of adding or substracting days from now()
$end=30;
return Domain::where('status', 'complete')
->where(function ($sql) use ((int) $start,(int) $end) {
$sql->whereDate('domain_expires_on', '>', Carbon::now()->subDays($start)->toDateString())
->whereDate('domain_expires_on', '<', Carbon::now()->addDays($end)->toDateString());
})
->get();
Also if you are storing domain_expires_on only as the date you should format the carbon date to match your database format.
above method will work for $table->date('domain_expires_on'); and $table->dateTime('domain_expires_on');

MySQL/PHP get average of past two months based on variable month

I'm trying to get an average of a value for the past 2 months, but not based on CURDATE()/NOW(). It would be dependent on what month the user was looking at in the application:
Ex:
If I'm looking at May, I would want the average of April and March.
If I'm looking at February, I would want the average of January and December (of the previous year).
I have a function that accepts the month and year of the page the user is on (it also accepts the emp_id, but that is irrelevant for this question).
public function getProtectedAmt($month,$year,$id){
$query = "SELECT avg(total_payout) as avg_payout FROM saved_plan_data WHERE emp_id = '$id' AND //this is where i dont know what to query for";
$result = mysql_query($query) or die(mysql_error());
$row = mysql_fetch_assoc($result);
return $row['avg_payout'];
}
In the table saved_plan_data, there are fields plan_month and plan_year that store INT values of what month/year the employee's total_payout is saved for.
How do I write my WHERE clause to get the AVG for the previous 2 months, depending on what the values of $month and $year are?
I think the easier and more readable solution is this one:
SELECT ...
FROM ...
WHERE
(plan_year, plan_month) IN ((2012, 12), (2013, 1))
You just need to compute the appropriate values.
This is also quite readable:
WHERE CONCAT_WS('-', plan_year, plan_month) IN ('2012-12', '2013-01')
In the function, create two variables $q_month & $q_year.
Set these as comma separated past two months. E.g. if currently the date is May 22, 2013, set the values to $q_month = 4,3 and $q_year = 2013
Use these variables in your query as WHERE Month in ($q_month) and Year in ($q_year)
Edit: Mis-read the question. This would get you the average for the last two months combined.
You could either be very verbose saying where (month and year) or (month and year)
SELECT avg(total_payout) as avg_payout
FROM saved_plan_data
WHERE emp_id=$id
AND (
(plan_month = $month1 AND plan_year = $year1)
OR (plan_month = $month2 AND plan_year = $year2)
)
Or you can cast the plan_month and plan_year as a date and check if the value is between two dates:
SELECT avg(total_payout) as avg_payout
FROM saved_plan_data
WHERE emp_id=$id
AND STR_TO_DATE(CONCAT_WS('-',plan_year,plan_month,'1'),'%Y-%m-%d')
BETWEEN '$year1-$month1-1' AND '$year2-$month2-1'
Also, you really should just store the month and year together. Here is a SO question with good answers about it: mysql datatype to store month and year only
I think the easiest way is to think of the year/month combinations as a number of months since year/month 0. That is, convert to number of months by multiplying the year times 12 and adding the months.
Then the previous two months is easy, and you don't have to worry about year boundaries:
SELECT avg(total_payout) as avg_payout
FROM saved_plan_data
WHERE emp_id = '$id' AND
plan_year*12 + plan_month in ($year*12+month - 1, $year*12+month - 2)

calculate difference between two date with php time() function in mysql query

I have searched about this but I could not find anything.
I have a article table. when I write new article I write time into mysql table with using php time() function.
my table is
id article time
time data type is INT(UNSIGNED)
my problem is I want to show articles from last week to today or from last month to today.
how my mysql query should be?
normally I do this
SELECT * FROM articles ORDER BY Time DESC
so this gives me data from today to past. how should I do this? I can't come up with a solution. should I use php-mysql together or can I handle this with only mysql? could you give me idea or example please? thanks.
edit:
I changed to datetime as suggested and now I think I have timezone problem
now my ago() function work 2 hours late.
<?php
date_default_timezone_set('Europe/Istanbul'); //timezone function
ago($time)
{
$periods = array("saniye", "dakka", "saat", "gün", "hafta", "ay", "yıl", "baya");
$lengths = array("60","60","24","7","4.35","12","10");
$now = time();
$difference = $now - $time;
$tense = "önce";
for($j = 0; $difference >= $lengths[$j] && $j < count($lengths)-1; $j++) {
$difference /= $lengths[$j];
}
$difference = round($difference);
return "$difference $periods[$j] önce ";
} //ago function
echo $Date = ago(strtotime($data['WriteTime'])). 'önce';
?>
Assuming your time column is a Unix timestamp, you can try something like this: (not tested)
SELECT ...
FROM magic
WHERE `time` BETWEEN DATE_SUB(FROM_UNIXTIME(`time`), INTERVAL 1 WEEK) AND NOW()
For your month, you would use INTERVAL 1 MONTH. Please, convert your column to common data types and don't use reserved words as the column names.
First make time a date type field
(and give it a meaningful different name like article_date for e.g)
Then use this query:
SELECT * FROM articles
WHERE article_date BETWEEN CURDATE() - INTERVAL 7 DAY AND CURDATE()
Well, you made a beginner mistake in using the unix timestamp integer for storage in your database. You should almost always use a date/datetime field type, because you invariably need to query against those fields which is much easier when not using unix timestamps.
So, convert your field to datetime, use MySQL's NOW() to insert current timestamps into the field when adding rows.
Then look at the MySQL data/time functions to query against thus field to your heart's desire.
http://dev.mysql.com/doc/refman/5.5/en/date-and-time-functions.html

Date comparison with PHP and Mysql

I have a table with a date field type date.
What I am trying to do is to do a comparison between the date from inside the table and the today date. If the date from the table is yesterday then insert the today date.
The thing I'm not sure about is how to insert the data in the database so I can make the comparison. here is what im thinking to do"
$d = time();
$x = mysql_querry("SELECT date FROM table where id = $id", $con);
while($y = myqsl_fetch_array($x)){
$oldTime = $y['date'];
}
if ($oldTime < $d){
$i = mysql_querry("INSERT INTO table (date) VALUES (CURDATE()) ", $con);
}
So, I'm not sure if $oldTime and $d can be compared like that, but I hope you guys get my point.
Any ideas?
Thanks
You can't do in that way because the CURDATE() function return a date in a format like 2011-11-11 while time() returns the number of seconds since the January 1 1970 00:00:00 GMT.
Anyway you can change the format of the time() to look like the CURDATE() using the date() function in this way:
date('Y-m-d', time())
or even better, to get the current date, you can use just this line:
date('Y-m-d')
To conclude, you can do the if in this way:
if( strtotime($oldTime) < strtotime(date('Y-m-d')) )
or even better:
if( strtotime($oldTime) < strtotime('now') )
To compare dates you can use strtotime($date); Where date can be a time(), mysql date or date('Y-m-d'); string

Optional month or day in MySQL date field from PHP

I have a problem where I need to handle dates where the month and day parts are optional. For example, the year will always be known but sometimes the day or month and day will be unknown.
In MySQL I can create a table with a date field and while I can't find any reference in the MySQL Manual it will accept the following as valid:
(YYYY-MM-DD format):
2011-02-10 // Current date
2011-02-00 // Day unknown so replaced with 00
2011-00-00 // Day and month unkown so replaced with 00-00
Test calculations from within the database work fine so I can still sort results easily. In the manual it says that month needs to be between 01 and 12, and day between 01 and 31 - but it does accept 00.
First question: Am I going to run into trouble using 00 in the month or day parts or is this perfectly acceptable?
Next question: Is there a PHP function (or MySQL format command) that will automatically format the following dates into the required format string?
2011 becomes 2011-00-00
2011-02 becomes 2011-02-00
Or do I need write a special function to handle this?
The following doesn't work:
<?php
$date = date_create_from_format('Y-m-d', '2011-00-00');
echo date_format($date, 'Y-m-d');
// Returns 2010-11-30
$date = date_create_from_format('Y-m-d', '2011-02-00');
echo date_format($date, 'Y-m-d');
// Returns 2011-01-31
?>
Third question: Is there a PHP function (or MySQL command) to format the dates for use in PHP?
Finally, is this the best approach? Or is there a 'best practise' method?
EDIT:
Here is what I'm currently doing:
A date field can accept a date in the format YYYY, YYYY-MM, or YYYY-MM-DD and before sending to the database it is processed in this function:
/**
* Takes a date string in the form:
* YYYY or
* YYYY-MM or
* YYYY-MM-DD
* and validates it
*
* Use date_format($date, $format); to reverse.
*
* #param string $phpDate Date format [YYYY | YYYY-MM | YYYY-MM-DD]
*
* #return array 'date' as YYYY-MM-DD, 'format' as ['Y' | 'Y-m' | 'Y-m-d'] or returns false if invalid
*/
function date_php2mysql($phpDate) {
$dateArr = false;
// Pattern match
if (preg_match('%^(?P<year>\d{4})[- _/.]?(?P<month>\d{0,2})[- _/.]?(?P<day>\d{0,2})%im', trim($phpDate), $parts)) {
if (empty($parts['month'])) {
// Only year valid
$date = $parts['year']."-01-01";
$format = "Y";
} elseif (empty($parts['day'])) {
// Year and month valid
$date = $parts['year']."-".$parts['month']."-01";
$format = "Y-m";
} else {
// Year month and day valid
$date = $parts['year']."-".$parts['month']."-".$parts['day'];
$format = "Y-m-d";
}
// Double check that it is a valid date
if (strtotime($date)) {
// Valid date and format
$dateArr = array('date' => $date, 'format' => $format);
}
} else {
// Didn't match
// Maybe it is still a valid date
if (($timestamp = strtotime($phpDate)) !== false) {
$dateArr = array('date' => date('Y-m-d', $timestamp), 'format' => "Y-m-d");
}
}
// Return result
return $dateArr;
}
So it pattern matches the input $phpDate where it must begin with 4 digits, then optionally pairs of digits for the month and the day. These are stored in an array called $parts.
It then checks if months or days exist, specifying the format string and creating the date.
Finally, if everything checks out, it returns a valid date as well as a format string. Otherwise it returns FALSE.
I end up with a valid date format for my database and I have a way of using it again when it comes back out.
Anyone think of a better way to do this?
I have a problem where I need to handle dates where the month and day parts are optional.
For example, the year will always be known but sometimes the day or month and day will be
unknown.
In many occasions, we do need such 'more or less precise' dates, and I use such dates as 2011-04-01 (precise), as well as 2011-04 (= April 2011) and 2011 (year-only date) in archives metadata. As you mention it, MySQL date field tolerates '2011-00-00' though no FAQs tell about it, and it's fine.
But then, I had to interface the MySQL database via ODBC and the date fields
are correctly translated, except the 'tolerated' dates (Ex: '2011-04-00' results empty in the resulting MySQL-ODBC-connected ACCESS database.
For that reason, I came to the conclusion that the MySQL date field could be converted in a plain VARCHAR(10) field : As long as we don't need specific MySQL date functions, it works fine, and of course, we can still use php date functions and your fine date_php2mysql() function.
I would say that the only case when a MySQL date field is needed
is when one needs complex SQL queries, using MySQL date functions in the query itself.
(But such queries would not work anymore on 'more or less precise' dates!...)
Conclusion : For 'more or less precise' dates,
I presently discard MySQL date field and use plain VARCHAR(10) field
with aaaa-mm-jj formated data. Simple is beautiful.
Since the data parts are all optional, would it be tedious to store the month, day, and year portions in separate integer fields? Or in a VARCHAR field? 2011-02-00 is not a valid date, and I wouldnt't think mysql or PHP would be excited about it. Test it out with str_to_time and see what kind of results you get, also, did you verify that the sorting worked right in MySQL? If the docs say that 1 through 31 is required, and it is taking 00, you might be relying on what is, in essence, a bug.
Since 2011-02-00 is not a valid date, none of PHP's formatting functions will give you this result. If it handled it at all, I wouldn't be surprised if you got 2001-01-31 if you tried. All the more reason to either store it as a string in the database, or put the month, day, and year in separate integer fields. If you went with the latter route, you could still do sorting on those columns.
I have also encountered this problem. I ended up using the PEAR Date package. Most date classes won't work with optional months or optional days, but the PEAR Date package does. This also means you don't need custom formatting functions and can use the fancy formatting methods provided by the Date package.
I have found this link in a textbook. This states that month and day values can be zero to allow for the possiblity of storing incomplete or unknown data
http://books.google.co.uk/books?id=s_87mv-Eo4AC&pg=PA145&lpg=PA145&dq=mysql+date+of+death+when+month+unknown&source=bl&ots=tcRGz3UDtg&sig=YkwpkAlDtBP1KKTDtqSyZCl63hs&hl=en&ei=Btf5TbL1NIexhAfkveyTAw&sa=X&oi=book_result&ct=result&resnum=8&ved=0CFMQ6AEwBw#v=onepage&q&f=false
If you pull your date in pieces from the database you can get it as if it's 3 fields.
YEAR(dateField) as Year, MONTH(dateField) as Month, DAY(dateField) as DAY
Then pushing those into the corresponding fields in the next bit of PHP will give you the result you're looking for.
$day = 0;
$month = 0;
$year = 2013;
echo $datestring;
$format = "Y";
if($month)
{
$format .= "-m";
if($day)
$format .="-d";
else
$day = 1;
}
else
{
$month = 1;
$day = 1;
}
$datestring = strval($year)."-".strval($month)."-".strval($day);
$date = date($format, strtotime($datestring));
echo $date; // "2013", if $month = 1, "2013-01", if $day and $month = 1, "2013-01-01"

Categories