fileparts Posted June 17, 2015 Share Posted June 17, 2015 I am currently working on a Calendar where it will be populated from Arrays that will be populated from a database. I currently have the Calendar look for a start date that is within the bookedStart Array and then set the variable booked as true until it finds an end date that is within the bookedEnd Array and then set the variable to false. The issue with this method is that it will only show what dates are booked, between a start and end date, if the start and end date are within the same month. How would I adapt my Calendar to allow it to work across months, for example: Here is the code I am working with: My Main Variables: //Labels $dayLabels = array("Monday","Tuesday","Wednesday","Thursday","Friday","Saturday","Sunday"); $dayMiniLabels = array("Mon","Tue","Wed","Thu","Fri","Sat","Sun"); $monthLables = array("January","February","March","April","May","June","July","August","September","October","November","December"); //max values $maxDays = 7; $maxMonths = 12; //stats $forceMonth = $_GET['m']; $forceYear = $_GET['y']; $todayDate = date("d-m-Y"); $todayDate = date("d-m-Y", strtotime($todayDate)); $explodeToday = explode("-", $todayDate); $currentDay = $explodeToday[0]; if(isset($forceMonth)) { $currentMonth = $forceMonth; } else { $currentMonth = $explodeToday[1]; }; if(isset($forceYear)) { $currentYear = $forceYear; } else { $currentYear = $explodeToday[2]; }; $currentDate = strtotime("01-$currentMonth-$currentYear"); $prevMonth = sprintf("%02d", $currentMonth - 1); $nextMonth = sprintf("%02d", $currentMonth + 1); $prevYear = sprintf("%02d", $currentYear - 1); $nextYear = sprintf("%02d", $currentYear + 1); $daysInMonth = cal_days_in_month(CAL_GREGORIAN, $currentMonth, $currentYear); $firstDayofMonth = date("D", $currentDate); $firstDayofMonth = array_search($firstDayofMonth, $dayMiniLabels); $firstDayofMonth = $firstDayofMonth; //database values $bookedStart = array(); $bookedEnd = array(); $bookedUser = array(); if($getBookings = $con->prepare("SELECT userID,bookingStart,bookingEnd FROM bookings WHERE machineID=?")) { $getBookings->bind_param("i", $_GET['id']); if($getBookings->execute()) { $getBookings->bind_result($bookingUserID,$bookingStart,$bookingEnd); while($getBookings->fetch()) { array_push($bookedStart, $bookingStart); array_push($bookedEnd, $bookingEnd); array_push($bookedUser, $bookingUserID); }; }; }; $getBookings->close(); //counters $daysIntoMonth = 0; $dayCounter = 0; $startMonth = 0; Here is the display code, "where the issue is": <table class="full grid dayLabels"> <tr> <?php foreach($dayLabels as $day) { echo '<td class="day"><p>' .$day. '</p></td>'; }; ?> </tr> </table> <table id="calendar" class="full grid calendar"> <?php while($daysIntoMonth < $daysInMonth) { //days into month $daysIntoMonth++; $temp_intoMonth = sprintf("%02d", $daysIntoMonth); $daysIntoMonth = $temp_intoMonth; //days into week $dayCounter++; $temp_dayCounter = sprintf("%02d", $dayCounter); $dayCounter = $temp_dayCounter; //current calendar date $calDate = date('d-m-Y', strtotime($daysIntoMonth. '-' .$currentMonth. '-' .$currentYear)); $calTime = strtotime($calDate); $todaysNumber = date('w', $timeCal); if($dayCounter == 1) { echo '<tr>'; }; if($firstDayofMonth != 7) { while($startMonth < $firstDayofMonth) { echo '<td class="padding"></td>'; $startMonth++; $dayCounter++; $temp_dayCounter = sprintf("%02d", $dayCounter); $dayCounter = $temp_dayCounter; }; }; if($startKey = in_array($calDate, $bookedStart, true)) { $booked = true; echo ' <td class="booked"> <p class="date">' .$daysIntoMonth. '</p> </td> '; } else if(in_array($calDate, $bookedEnd, true)) { $booked = false; echo ' <td class="booked"> <p class="date">' .$daysIntoMonth. '</p> </td> '; } else if($booked == true) { echo ' <td class="booked"> <p class="date">' .$daysIntoMonth. '</p> </td> '; } else { echo ' <td> <p class="date">' .$daysIntoMonth. '</p> </td> '; }; if($dayCounter == $maxDays) { echo '</tr>'; $dayCounter = 0; }; }; ?> </table> tl;dr - if a booking runs over a month, the start date isn't shown on the ending month, but the end date is, because of how I have it check between dates, it won't highlight the days before the end date. Note: This is on an internal server, so it doesn't have to worry about SQL Injection. Thanks in advance, fp Quote Link to comment https://forums.phpfreaks.com/topic/296874-adapting-my-calendar-to-work-across-more-than-1-month/ Share on other sites More sharing options...
mac_gyver Posted June 17, 2015 Share Posted June 17, 2015 (edited) you need to use dates with a YYYY-MM-DD format, so that you can do greater-than/less-than comparisons. your dates should be stored in the database using a DATE data type, which will give them that format. this will let you retrieve only the rows that have a start to end date range that matches the year-month you are trying to display. next, just store the retrieved data directly in one php array, with the id, start date, and end date. as you loop over the days in a month to display the calendar, you will form the current date with a YYYY-MM-DD format. for each day, you will then loop over the array of data and retrieve the id(s) where the current date is between the start date and the end date. edit: an alternate method would be to expand the start date to end date into individual dates within the range and for those dates that correspond to the year-month being displayed (dates before and after the current year-month would not need to be stored), store the id as an array element for each day, using the date as the main array key. this would result in an array that looks like - $array['2015-06-01'][] = some_id; // some_id is booked on the 1st and 2nd of this month $array['2015-06-01'][] = someother_id; // someother_id is booked on the 1st of this month $array['2015-06-02'][] = some_id; as you loop over the days in the month, just loop over any sub-array of id's, if present, that have a main array key matching that current date. Edited June 17, 2015 by mac_gyver Quote Link to comment https://forums.phpfreaks.com/topic/296874-adapting-my-calendar-to-work-across-more-than-1-month/#findComment-1514159 Share on other sites More sharing options...
fileparts Posted June 17, 2015 Author Share Posted June 17, 2015 you need to use dates with a YYYY-MM-DD format, so that you can do greater-than/less-than comparisons. your dates should be stored in the database using a DATE data type, which will give them that format. this will let you retrieve only the rows that have a start to end date range that matches the year-month you are trying to display. next, just store the retrieved data directly in one php array, with the id, start date, and end date. as you loop over the days in a month to display the calendar, you will form the current date with a YYYY-MM-DD format. for each day, you will then loop over the array of data and retrieve the id(s) where the current date is between the start date and the end date. edit: an alternate method would be to expand the start date to end date into individual dates within the range and for those dates that correspond to the year-month being displayed (dates before and after the current year-month would not need to be stored), store the id as an array element for each day, using the date as the main array key. this would result in an array that looks like - $array['2015-06-01'][] = some_id; // some_id is booked on the 1st and 2nd of this month $array['2015-06-01'][] = someother_id; // someother_id is booked on the 1st of this month $array['2015-06-02'][] = some_id; as you loop over the days in the month, just loop over any sub-array of id's, if present, that have a main array key matching that current date. Thanks for the response, certainly an interesting idea. How about a way to check to see if a bookedStart date and bookedEnd date have the same position in their respective arrays and then checking if bookedEnd date's month is greater than bookedStart date's month, then - somehow, the dates between these two dates become highlighted? Possibly simplar than your answer, although I wouldn't know where to start with coding it. Quote Link to comment https://forums.phpfreaks.com/topic/296874-adapting-my-calendar-to-work-across-more-than-1-month/#findComment-1514162 Share on other sites More sharing options...
Solution Barand Posted June 17, 2015 Solution Share Posted June 17, 2015 Here is how I would create an array of booked dates for a month $monthStart = date('Y-m-01'); $monthEnd = date('Y-m-t'); $bookings = array(); // CREATE DATE PERIOD FOR THE MONTH $s = new DateTime($monthStart); $e = new DateTime("$monthEnd + 1 days"); $oneday = new DateInterval('P1D'); $dp = new DatePeriod($s, $oneday, $e); // INITIALIZE BOOKINGS ARRAY FOR MONTH foreach ($dp as $d) { $bookings[$d->format('Y-m-d')] = ''; } // FIND BOOKING WHICH ARE ALL OR PART IN THIS MONTH $sql = "SELECT userID , bookingStart , bookingEnd FROM bookings WHERE machineID = ? AND bookingStart < ? AND bookingEnd > ? "; $getBookings = $con->prepare($sql); $getBookings->bind_param('iss', $_GET['id'], $monthEnd, $monthStart); $getBookings->execute(); $getBookings->bind_result($uid, $bstart, $bend); while ($getBookings->fetch()) { $s = new DateTime(max($bstart, $monthStart)); // FIND THE START AND END $e = new DateTime(min($bend, $monthEnd)); // DATES WITHIN THE MONTH $e->modify('+1 day'); $dp = new DatePeriod($s, $oneday, $e); // DATE PERIOD FOR THE BOOKING foreach ($dp as $d) { // STORE userid IN THE DAYS BOOKED $bookings[$d->format('Y-m-d')] = $uid; } } which gives an array, indexed by date, showing the user who has booked the machine Array ( [2015-06-01] => 2 [2015-06-02] => 2 [2015-06-03] => 2 [2015-06-04] => 2 [2015-06-05] => 2 [2015-06-06] => 2 [2015-06-07] => 2 [2015-06-08] => 2 [2015-06-09] => [2015-06-10] => 3 [2015-06-11] => 3 [2015-06-12] => 3 [2015-06-13] => [2015-06-14] => [2015-06-15] => 4 [2015-06-16] => 4 [2015-06-17] => 4 [2015-06-18] => 4 [2015-06-19] => 4 [2015-06-20] => 4 [2015-06-21] => 4 [2015-06-22] => 4 [2015-06-23] => 4 [2015-06-24] => [2015-06-25] => [2015-06-26] => [2015-06-27] => [2015-06-28] => 5 [2015-06-29] => 5 [2015-06-30] => 5 ) from this data +-------------+--------+-----------+--------------+------------+ | bookings_id | userID | machineID | bookingStart | bookingEnd | +-------------+--------+-----------+--------------+------------+ | 1 | 1 | 1 | 2015-05-20 | 2015-05-31 | previous month | 2 | 2 | 1 | 2015-05-28 | 2015-06-08 | starts in prev month | 3 | 3 | 1 | 2015-06-10 | 2015-06-12 | | 4 | 4 | 1 | 2015-06-15 | 2015-06-23 | | 5 | 5 | 1 | 2015-06-28 | 2015-07-10 | ends in next month | 6 | 6 | 1 | 2015-07-11 | 2015-07-20 | next month +-------------+--------+-----------+--------------+------------+ Quote Link to comment https://forums.phpfreaks.com/topic/296874-adapting-my-calendar-to-work-across-more-than-1-month/#findComment-1514173 Share on other sites More sharing options...
fileparts Posted June 17, 2015 Author Share Posted June 17, 2015 Here is how I would create an array of booked dates for a month $monthStart = date('Y-m-01'); $monthEnd = date('Y-m-t'); $bookings = array(); // CREATE DATE PERIOD FOR THE MONTH $s = new DateTime($monthStart); $e = new DateTime("$monthEnd + 1 days"); $oneday = new DateInterval('P1D'); $dp = new DatePeriod($s, $oneday, $e); // INITIALIZE BOOKINGS ARRAY FOR MONTH foreach ($dp as $d) { $bookings[$d->format('Y-m-d')] = ''; } // FIND BOOKING WHICH ARE ALL OR PART IN THIS MONTH $sql = "SELECT userID , bookingStart , bookingEnd FROM bookings WHERE machineID = ? AND bookingStart < ? AND bookingEnd > ? "; $getBookings = $con->prepare($sql); $getBookings->bind_param('iss', $_GET['id'], $monthEnd, $monthStart); $getBookings->execute(); $getBookings->bind_result($uid, $bstart, $bend); while ($getBookings->fetch()) { $s = new DateTime(max($bstart, $monthStart)); // FIND THE START AND END $e = new DateTime(min($bend, $monthEnd)); // DATES WITHIN THE MONTH $e->modify('+1 day'); $dp = new DatePeriod($s, $oneday, $e); // DATE PERIOD FOR THE BOOKING foreach ($dp as $d) { // STORE userid IN THE DAYS BOOKED $bookings[$d->format('Y-m-d')] = $uid; } } which gives an array, indexed by date, showing the user who has booked the machine Array ( [2015-06-01] => 2 [2015-06-02] => 2 [2015-06-03] => 2 [2015-06-04] => 2 [2015-06-05] => 2 [2015-06-06] => 2 [2015-06-07] => 2 [2015-06-08] => 2 [2015-06-09] => [2015-06-10] => 3 [2015-06-11] => 3 [2015-06-12] => 3 [2015-06-13] => [2015-06-14] => [2015-06-15] => 4 [2015-06-16] => 4 [2015-06-17] => 4 [2015-06-18] => 4 [2015-06-19] => 4 [2015-06-20] => 4 [2015-06-21] => 4 [2015-06-22] => 4 [2015-06-23] => 4 [2015-06-24] => [2015-06-25] => [2015-06-26] => [2015-06-27] => [2015-06-28] => 5 [2015-06-29] => 5 [2015-06-30] => 5 ) from this data +-------------+--------+-----------+--------------+------------+ | bookings_id | userID | machineID | bookingStart | bookingEnd | +-------------+--------+-----------+--------------+------------+ | 1 | 1 | 1 | 2015-05-20 | 2015-05-31 | previous month | 2 | 2 | 1 | 2015-05-28 | 2015-06-08 | starts in prev month | 3 | 3 | 1 | 2015-06-10 | 2015-06-12 | | 4 | 4 | 1 | 2015-06-15 | 2015-06-23 | | 5 | 5 | 1 | 2015-06-28 | 2015-07-10 | ends in next month | 6 | 6 | 1 | 2015-07-11 | 2015-07-20 | next month +-------------+--------+-----------+--------------+------------+ Thanks for the great response. I still would need to put this in a tabular format, 7 columns etc, to make a calendar which I would be able to read from. How would you go about outputting the data so that it can be read within a html table? Quote Link to comment https://forums.phpfreaks.com/topic/296874-adapting-my-calendar-to-work-across-more-than-1-month/#findComment-1514181 Share on other sites More sharing options...
fileparts Posted June 17, 2015 Author Share Posted June 17, 2015 Okay thanks @barand for the answer, I've tweaked and added bits to get it to display as a calendar. Here's what I've got: $dayLabels = array("Monday","Tuesday","Wednesday","Thursday","Friday","Saturday","Sunday"); $dayMiniLabels = array("Mon","Tue","Wed","Thu","Fri","Sat","Sun"); $monthLables = array("January","February","March","April","May","June","July","August","September","October","November","December"); $forceMonth = $_GET['m']; $forceYear = $_GET['y']; if(isset($forceMonth)) { if(strlen($forceMonth) == 1) { $forceMonth = sprintf("%02d", $forceMonth); }; $currentMonth = $forceMonth; } else { $currentMonth = date("m"); }; if(isset($forceYear)) { if(strlen($forceYear) == 2) { $dt = DateTime::createFromFormat('y', $forceYear); $forceYear = $dt->format('Y'); }; $currentYear = $forceYear; } else { $currentYear = date("Y"); }; $monthStart = date($currentYear. '-' .$currentMonth. '-01'); $monthEnd = date($currentYear. '-' .$currentMonth. '-t'); $prevMonth = sprintf("%02d", $currentMonth - 1); $nextMonth = sprintf("%02d", $currentMonth + 1); $prevYear = sprintf("%02d", $currentYear - 1); $nextYear = sprintf("%02d", $currentYear + 1); $firstDayofMonth = date("D", $currentDate); $firstDayofMonth = array_search($firstDayofMonth, $dayMiniLabels); $firstDayofMonth = $firstDayofMonth; $bookings = array(); $s = new DateTime($monthStart); $e = new DateTime("$monthEnd + 1 days"); $oneday = new DateInterval('P1D'); $dp = new DatePeriod($s, $oneday, $e); foreach ($dp as $d) { $bookings[$d->format('Y-m-d')] = ''; }; $sql = "SELECT userID , bookingStart , bookingEnd FROM bookings WHERE machineID = ? AND bookingStart < ? AND bookingEnd > ?"; $getBookings = $con->prepare($sql); $getBookings->bind_param('iss', $_GET['id'], $monthEnd, $monthStart); $getBookings->execute(); $getBookings->bind_result($uid, $bstart, $bend); while ($getBookings->fetch()) { $s = new DateTime(max($bstart, $monthStart)); $e = new DateTime(min($bend, $monthEnd)); $e->modify('+1 day'); $dp = new DatePeriod($s, $oneday, $e); foreach ($dp as $d) { $bookings[$d->format('Y-m-d')] = $uid; }; }; $dayCount = 0; $startMonth = 0; $calDate = 0; echo '<table>'; foreach($bookings as $date) { $dayCount++; $calDate++; $calDate = sprintf("%02d", $calDate); if($dayCount == 1) { echo '<tr>'; }; if($firstDayofMonth != 7) { while($startMonth < $firstDayofMonth) { echo '<td class="padding"></td>'; $startMonth++; $dayCount++; $temp_dayCount = sprintf("%02d", $dayCount); $dayCount = $temp_dayCount; }; }; echo '<td>' .$calDate. '</td>'; if($dayCount == 7) { echo '</tr>'; $dayCount = 0; }; }; echo '</table>'; Any changes that I should make? Quote Link to comment https://forums.phpfreaks.com/topic/296874-adapting-my-calendar-to-work-across-more-than-1-month/#findComment-1514186 Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.