Date query and display - php

I am currently trying to write a little program to track time-off requests for employees. I'm fairly new to MYSQL and PHP, so it's a learning project for me as well. I've run into this problem which I do not seem to be able to figure out.
I want to display time off requests for a given week (Mon-Fri). I've got the requests in a table 'requests', with a 'Starttime' and 'Endtime' in separate fields, both Date/Time.
I can currently easily search and retrieve requests that have either (or both) Starttime or Endtime values that fall within the given ISO week I am looking at (WEEKOFYEAR() ).
What I need to be able to do is search for requests that may include days in the ISO week I am displaying, but not have a Starttime or Endtime during that week.
Example:
Employee takes off Tuesday of Week 24 through Friday of Week 24.
Currently, I would correctly display that the employee was off starting Tuesday and show a return on that Friday, but on Wed and Thursday nothing would be entered.
Employee takes off Friday of Week 30 through Monday of Week 32.
Currently, I would show that employee as not being 'off' during Week 31 because the search would not show a Starttime or Endtime during that week even though they are actually off the entire week. Though the Starttime and Endtime would be noted on the correct days.
Right now, what I do to work around this is run 5 additional queries to check if the date for each day Mon-Fri during Week 31 is contained BETWEEN the Starttime and Endtime of each request in the db.
I hate to run a total of 6 queries to get this information. Is there an easier way to get that information?

I just wrote a calendar app for events and ran into this- how bout something like this:
SELECT * FROM Requests WHERE
Start_Date BETWEEN <first_day_of_week> AND <last_day_of_week>
OR
End_Date BETWEEN <first_day_of_week> AND <last_day_of_week>
OR
<day_of_week_monday> BETWEEN Start_Date AND End_Date
OR
<day_of_week_tuesday> BETWEEN Start_Date AND End_Date
OR
<day_of_week_wedenesday> BETWEEN Start_Date AND End_Date
OR
<day_of_week_thursday> BETWEEN Start_Date AND End_Date
OR
<day_of_week_friday> BETWEEN Start_Date AND End_Date
GROUP BY ID ORDER BY Start_Date ASC, Date ASC
While < value_names > are generated with php via the currently viewed week requested. Should cover your bases.

What format are these dates stored in the DB? Assuming they are using MySQL's DATE format, its pretty easy to do. You can just use comparison operators on the fields and MySQL will do the work for you in one query.
$sql = "SELECT * FROM table WHERE startdate <= $someday AND $someday <= enddate";

Sticking to your week of year way of doing it, you can run a check to see if the current week falls within the range of the starting week off and the ending week off.
SELECT * FROM table WHERE WEEKOFYEAR(Starttime) <= N AND WEEKOFYEAR(Endtime) >= N;
(where N is the week you're displaying)
What you'd want to do, once you get the rows, is parse each day in PHP to see if that day falls between the starttime and endtime.
A good method for that is using:
$start_timestamp = strtotime($row['Starttime']);
$end_timestamp = strtotime($row['Endtime']);
You can use a similar method to get a timestamp of the day you are displaying, and see if it falls between $start_timestamp and $end_timestamp to determine if that day is off.

since you mentioned PHP as the display:
$start=30; //Friday of Week 30
$end=32; //Monday of Week 32
foreach (range($start, $end) as $number) {
echo $number;
}
You would expect to get 30,31,32.
You will have to verify that $start is < $end though as well for December to January weeks.
The range for WEEKOFYEAR() is 1-53. In this case, add 53 to the $end and display mod of $end if greater than 53:
$start=52; //Friday of Week 52, 2009
$end=2; //Monday of Week 2, 2010
If($start>$end) $end+=53;
foreach (range($start, $end) as $number) {
if($number>53){
echo $number%53;}
else{
echo $number;
}
}
You would expect to get 52,53,1,2

Probably need the query to read either like the big one with all the ORs or something like this
WHERE
Starttime <= <value for last day/time of the week>
AND
Endtime >= <value for the first day/time of the week>
That should get all the dates you need that could fall in that week, then you parse the records you get with PHP to find the ones for that actual week... though there may be an easier way to do that.

Related

Compare date with next month date in php

I have a query, A user fill records of every day for each month and I want, the user can edit/delete his data till 7th of next month.
I got the diff between dates using date() function, but can't understand how to compare that record fill date is less than 7th of next month.
//$fill_date; get data filled date from database
$filled_date = date("Y-m-d", strtotime($fill_date));
$datestring = $filled_date.' first day of next month';
$dt=date_create($datestring);
$d_mont = $dt->format('Y-m-07'); // give 7th of next month from data insert date
//get next month from fill date
$f_date = date('Y-m-d' , strtotime($fill_date));
if(strtotime($f_date) <= strtotime($d_mont)) {
echo strtotime($f_date)." <= ".strtotime($d_mont);
echo "you can edit";
}
There I share a query which can fetch the data till 7th.May this query help you if found any issue then comment.
this table contains last data till 7th of every month otherwise
no data.
SELECT * from datatable where day(curdate()) <= 7 and cast(datefield as date) >= (curdate() + interval -1 month);
Here is an example code
$curdate = date('Y-m-d', strtotime($fill_date)); // or time() for current date
$month = date('m', strtotime($curdate));
$year = date('Y', strtotime($curdate));
$nextmonth = ($month == 12)? 1: $month+1;
$date2 = date("Y-m-d", mktime(0, 0, 0, $nextmonth, 7, $year));
You can compare the dates with strtotime as you already do
What your asking to do is very confusing, but I understand, because I am cool like that.
The best way to do this to set a flag in the data, have a field in the database that is called locked or such that is a simple boolen value 1=true, 0=false
Then on the 7th of the month at midnight run a cron job that updates all the records before the current month with a 0 and set them to a 1.
It would be pretty trivial to write a cron job to do that maybe 20 lines of code tops.
Brief example (psudo code)
$date = (new DateTime())->modify('first day of this month')->format('Y-m-d');
$Sql = "UPDATE tbl SET locked = 1 WHERE DATE(date_field) < '{$date}' AND locked=0";
$DB->query($Sql);
Cron: if you don't know what it is
https://en.wikipedia.org/wiki/Cron
Use cron to schedule jobs (commands or shell scripts, including PHP )
to run periodically at fixed times, dates, or intervals.
If they can only edit tell the 7th of the next month, then on the 7th of each month all the data from last month is no longer editable.
Then when you pull them to edit, you just do
SELECT * FROM table WHERE locked = 0
That is if you truly what it to stop on the 7th and not a month. AS I said in the comments if I put a record on the 1st that gives me that whole month + 7 days, if I did it on the last day, I would have only 7 days to edit the record.
It's not as trivial to write a date range query for this as it first seems. Because if it's before the 7th, you have to select everything from last month and everything from this month ( tell the current date ). But if it's the 8th, you have to select everything from the beginning of the month tell the current data ( omitting last month ). So the query would change depending on the day it currently is.
To try to filter the data after pulling it out seems like a waste, because you will always pull more records then the user can edit, and then you have to work out the date switch anyway.
An advantage of having a locked field also, it that you can selectively unlock a record for a user so they could edit it again, just by fliping the 1 back to a 0. ( -note- the cron job I outlined above would re-lock it ) The point is it would be possible to allow them to edit specific records without code changes.
IMO, it's the best way to do it.

Display only future database records with MySQL

I am trying to display only records two weeks in advance from the current date onwards. starttime is stored as a datetime data type in the database.
I have this,
SELECT id, date_format(starttime, '%d-%m-%Y %H:%i') AS formatted_start, date_format(starttime, '%Y-%m-%d') AS formatted_date,
date_format(endtime, ' %H:%i') AS formatted_end
FROM timedates WHERE user_id = 1 AND `status`='' AND YEARWEEK(formatted_date, 0) IN (YEARWEEK(NOW(), 0),
YEARWEEK(DATE_ADD(NOW(), INTERVAL 2 WEEK), 0))
But I am getting a syntax error YEARWEEK(formatted_date, 0) IN (YEARWEEK(NOW(), 0) AND YEARWEEK(DATE_ADD(NOW()
Could anyone tell me what's wrong with it?
It seems MySQL does not support calculated column in the where clause:
try
SELECT id, date_format(starttime, '%d-%m-%Y %H:%i') AS formatted_start,
date_format(starttime, '%Y-%m-%d') AS formatted_date,
date_format(endtime, ' %H:%i') AS formatted_end
FROM timedates
WHERE user_id = 1 AND `status`='' AND
YEARWEEK(starttime, 0) IN (
YEARWEEK(DATE_ADD(NOW(), INTERVAL 1 WEEK), 0),
YEARWEEK(DATE_ADD(NOW(), INTERVAL 2 WEEK), 0))
use starttime instead of formatted_date
As I said, I see no reason to use YEARWEEK function. You need start date set to today which is CURDATE() and plus 2 weeks period which is DATE_ADD(CURDATE(), INTERVAL 2 WEEK) and then we just check if starttime between those 2 dates.
SELECT id, date_format(starttime, '%d-%m-%Y %H:%i') AS formatted_start,
date_format(starttime, '%Y-%m-%d') AS formatted_date,
date_format(endtime, ' %H:%i') AS formatted_end
FROM timedates
WHERE user_id = 1
AND `status`=''
AND DATE(starttime) BETWEEN CURDATE() AND DATE_ADD(CURDATE(), INTERVAL 2 WEEK)
How do you define "two weeks in advance"? Our normal inclination, is to think "within two weeks", which would be to simply before 14 days from now.
WHERE starttime >= NOW()
AND starttime < NOW() + INTERVAL 14 DAY
But the original query is using YEARWEEK function, and the behavior with that is a bit different.
If today is Thursday, May 21, 1015. What is the range of dates that starttime should fall into?
For datetimes right now or in the future, we can just do:
WHERE starttime >= NOW()
(We can do just a > rather than >= if we want to exclude startime values that are an exact match for NOW().
The question is, the bit about "two weeks in advance". Adding 14 days, or 2 weeks, would get us up to Thursday, June 4, 2015. It looks like you might also want to include Friday and Saturday, June 5th and 6th. (Up until Sunday, June th.)
We can use an expression to return "Sunday on or following 14 days from today"
If it's a Sunday, we just use that date. (For convenience, we think of that as adding 0 days). If it's Saturday, we need to add 1 day. If it's a Friday, add 2 days, ... Monday, add 6 days.
Conveniently, the expression 6 - WEEKDAY(NOW()) gives us the number of days we need to add to today's date to get to the next Sunday.
Reference: https://dev.mysql.com/doc/refman/5.5/en/date-and-time-functions.html#function_weekday
We probably want to lop the time off at midnight, we can use the DATE() function to do that.
-- startime values on or after now and before midnight
-- of the first sunday on or after the date two weeks from now
WHERE starttime >= NOW()
AND starttime < DATE(NOW()) + INTERVAL 14+6-WEEKDAY(NOW()) DAY
It's much easier to read and understand what the query is doing when we reference bare columns from the table on one side, and do the gyration and manipulation on the other side. It's also easier to test. And, maybe more importantly, it allows MySQL to make effective use of an "range scan" operation on a suitable index, rather than having to evaluate a function on every row in the table.
If today is '2015-05-21', and what you meant by "two weeks in advance" was up until the second Sunday from now (Sunday, May 31, 2015... 1 week and 3 days from now) just replace the 14 with 7.
Again, it really depends on how you define "two weeks in advance", how you determine what that ending date boundary is. Once you can define that, you can write an expression that returns the value, and just compare to value stored in the starttime column.

Select SQL item with date within current week

We have a database of films, and need to select the film with a start and end date within the current week. We have two columns in the SQL table, both of type "date", and are written in the format 2015-01-25 (ISO)(YYYY-MM-DD). We need to select the entry that occurs within the current week. The start date for the film is usually the Friday of the week, and the end date is usually the Sunday of the week. I want to be able to show what the upcoming film for the upcoming weekend will be, no matter what day of the week they check. I have written the following PHP and SQL query, but I'm not getting any data back when I echo the $result.
$date = strtotime("now");
$last = strtotime('next Sunday');
$date = date('Y-m-d',$date);
$last = date('Y-m-d',$last);
$result = mysql_fetch_array(mysql_query("SELECT * FROM campusFilms WHERE startDate BETWEEN $date AND $last"));
Any assistance would be greatly appreciated, and I am happy to elaborate on anything needed. I have searched other StackOverflow questions but none of them quite answered this specific case.
SELECT *
FROM campusFilms
WHERE WEEK('2015-02-05') BETWEEN WEEK(startDate) AND WEEK(endDate);
http://sqlfiddle.com/#!2/476d3/3
This solution cannot use an index so, if performance is an issue, we can look at alternative solutions.
Why not just use YEARWEEK() ?
SELECT whatever_you_need
FROM campusFilms
WHERE YEARWEEK(CURDATE()) BETWEEN YEARWEEK(startDate) AND YEARWEEK(endDate);
yearweek returns the year and week of any given date which will handle multiple years.
If all you care is to find records where startdate is between the Friday and Sunday of the current week, then you don't even need to use PHP to compute dates, you can get mysql to do all the work for you:
SELECT *
FROM campusFilms
WHERE startDate BETWEEN
DATE_ADD(CURDATE(), INTERVAL(-2 + MOD(8-DAYOFWEEK(CURDATE()),7)) DAY)
AND
DATE_ADD(CURDATE(), INTERVAL(MOD(8-DAYOFWEEK(CURDATE()),7)) DAY)
This works regardless of what day of the week it is today. If it's Friday, it'll give you films between today and the day after tomorrow. For Saturdays, it'll give you films between yesterday and tomorrow and for Sundays, it'll give you films between two days ago and today.

mysql date show results today/yesterday/week

I am retrieving data from a table and show the total SUM of entries. What I want to do is to show the total SUM of entries made on today's date, yesterday and this month. The table is using the unix timestamp format (e.g. 1351771856 for example).
Currently I am using this line to show todays results:
AND comment_date > UNIX_TIMESTAMP() - 24 * 3600";
but that gives me just the entries for the last 24 hours.
Example: So let's say its Friday, 17:00 PM - it gives me the count from Thursday 17:00 PM to Friday 17:00 PM
What I want is to get the results for
Thursday 00:00:00 - 23:59:59 (yesterday in this case)
the results for today (00:00:00 - 23:59:59)
and last week, results that start on Monday, 00:00:00 until "today" (in this case Friday).
I couldn't find a way in the MySQL documentation to achieve this.
This mysql code should work for you:
// Today
AND DATE(from_unixtime(comment_date)) = CURRENT_DATE
// Yesterday
AND DATE(from_unixtime(comment_date)) = DATE_SUB(CURRENT_DATE,INTERVAL 1 DAY)
// This week
AND YEARWEEK(from_unixtime(comment_date), 1) = YEARWEEK(CURRENT_DATE, 1)
// This month
AND YEAR(from_unixtime(comment_date)) = YEAR(CURRENT_DATE)
AND MONTH(from_unixtime(comment_date)) = MONTH(CURRENT_DATE)
Simply use this:
AND comment_date > date_sub(current_date, interval 1 day)
See my answer here, I think it's quite related.
Pull records from orders table for the current week
Consider getting intimate with MySQL's GROUP BY. You will most likely need to know this if you use MySQL.

MySQL: Calculate the difference between Date/Times - only during M-F "Work week"

I need to calculate a difference between a starting date/time and an ending date/time. But, I only want to do this for the 5-day work week (exclude Sat/Sun as days). What is the best way to do this? My thought is that from the date, I'll have to get the day of the week and if it is a weekday, then I add to the accumulator. If it's not, then I don't add anything.
I'm sure someone has done this before, but I couldn't seem to find anything searching. Any links or other help would be very useful.
Many thanks,
Bruce
DAYOFWEEK returns 1 for Sunday and 7 for Saturday. I'm not sure how your schema is set up, but this will perform a TIMEDIFF of two dates that are on a Monday - Friday work week.
select TIMEDIFF(date1,date2) from table
where DAYOFWEEK(date1) not in (1,7) and DAYOFWEEK(date2) not in (1,7)
MySQL DATE/TIME functions
EDIT: From Bruce's comment about holidays. If you have a table full of holiday dates, something like this would work to exclude processing those days:
select TIMEDIFF(date1,date2) from table
where date1 not in (select holiday from holiday_table) and
date2 not in (select holiday from holiday_table) and
DAYOFWEEK(date1) not in (1,7) and DAYOFWEEK(date2) not in (1,7)
NETWORKDAYS() "Returns the number of whole working days between start_date and end_date. Working days exclude weekends and any dates identified in holidays. Use NETWORKDAYS to calculate employee benefits that accrue based on the number of days worked during a specific term." according to the Excel 2007 help file.
The "between" description is a bit inaccurate because it includes the start and end dates, i.e. networkdays(21-01-2010. 22-01-2010) = 2. It also takes no account of times.
Here's a function in PHP that will give the same results. It doesn't work properly if the end date is less than the start date, nor does do anything about holidays (see below the function).
function networkdays($startdate, $enddate)
{
$start_array = getdate(strtotime($startdate));
$end_array = getdate(strtotime($enddate));
// Make appropriate Sundays
$start_sunday = mktime(0, 0, 0, $start_array[mon], $start_array[mday]+(7-$start_array[wday]),$start_array[year]);
$end_sunday = mktime(0, 0, 0, $end_array[mon], $end_array[mday]- $end_array[wday],$end_array[year]);
// Calculate days in the whole weeks
$week_diff = $end_sunday - $start_sunday;
$number_of_weeks = round($week_diff /604800); // 60 seconds * 60 minutes * 24 hours * 7 days = 1 week in seconds
$days_in_whole_weeks = $number_of_weeks * 5;
//Calculate extra days at start and end
//[wday] is 0 (Sunday) to 7 (Saturday)
$days_at_start = 6 - $start_array[wday];
$days_at_end = $end_array[wday];
$total_days = $days_in_whole_weeks + $days_at_start + $days_at_end;
return $total_days;
}
To take holidays into account, you'd have to work out the number of days using this function, then use a query like
Select count (holiday_date) from holidays
where holiday_date between start_date and end_date
and DAYOFWEEK(holiday_date) not in (1,7)
Be careful that there isn't a problem with the end_date being treated as 00:00 (i.e. first thing in the morning) - you may have to condition it to be 23:59:59 so that it works properly. It all depends on how your holidays are stored.
To return the holidays in the same time period and subtract that from the number you first thought of.

Categories