PHP grouping by "bi weekly" - php

I have a report that calculates employee working hours by retrieving date, punch in and punch out and calculate duration, this data is saved into an array to be displayed based on the payroll period, here is the code that calculates payments based on a weekly period (looping within array)
foreach($punch_sets as $val){
if ($currentmonth==""){
echo "<tr><td>" . date("W",strtotime($val['in_date'])) . "</td>";
}
if ($currentmonth1 == date("F",strtotime($val['in_date'])) || $currentmonth1 ==""){
if ($currentmonth == date("W",strtotime($val['in_date'])) || $currentmonth==""){
$total_time += $minSec + $hours*3600;
$currentmonth = date("W",strtotime($val['in_date']));
}
else
{
echo "<td>" . sec2hm($total_time) . "</td>";
echo "<td>" . (sec2hm($total_time) * $ratepaid) . "</td></tr></tr>";
$currentmonth ="";
$total_time = $minSec + $hours*3600;
}
}
else {
$total_time = $minSec + $hours*3600;
}
$currentmonth1 = date("F",strtotime($val['in_date']));
}
The question here how do I adjust this logic to get bi weekly calculation instead of weekly.

Instead of using:
date("W",strtotime($val['in_date']))
To group by, group by:
floor(date("W",strtotime($val['in_date']))/2);
You might want to change $currentmonth to $currentperiod to reflect the change from the original script from monthly to weekly to now bi-weekly.

Related

How to get an employee's attendance if it does not log out on a particular date

I am looking for some basic attendance logic. What I have done so far is that employees can click on two different kinds of buttons and mark themselves as Signed In, Signed Out (status 1 and 2) using one button and Break Start, Break Over (status 3 and 4) using the other button.
Now when I calculate employee's total Sign In hours and total Break hours for a particular date I do something like below.
First iterate over a loop of Starting date and Ending date for which I want to see the working hours.
Now first of all check if the employee logged in on a particular date, by finding a status 1 entry of that date.
If the employee logged in on that date, then I fetch all attendance records for that date.
Now I iterate over this date's attendance records add up the time differences starting from first status 1 (i.e. Login) to next status and from next status (which can be either a break start 3 or a log out 2) till the next status (which can be either break over 4 or log in 1).
This is working good and my working hours' calculations are coming fine.
There is however one logical part that I am not able to understand i.e. if the employee does not logout on the same date for which I have fetched out the records, then the time span from last login or break start till the logout are not getting calculated. Because the final logged out status does not fall on the same date for which I fetched the records.
So, I need some help in understanding any suggestions how this can be managed and how can I calculate the working hours if the employee's logout status falls on a different date than login date.
Thanks in advance.
Here is some code.
public function getEmployeeAttendance($company_uid , $emp_uid)
{
for($m=1; $m<=12; $m++)
{
$mon = strtotime(date('Y-' . $m . '-00'));
$first = date("Y-m-01", $mon); // First Date Of cuRRENT mONTH
$last = date("Y-m-t", $mon); // Last Date Of cuRRENT mONTH
$date[] = range_date($first, $last);
}
$atten = array();
//echo "<pre>";
foreach($date as $dt)
{
foreach($dt as $d)
{
// A function to check if there was a status 1 on this date
$myAttendance = $this->Attendance_Model->myAttendance($company_uid , $emp_uid, $d);
# If Employee Signed In on This Date (i.e. Status was 1)
if(count($myAttendance) >0)
{
# Calculate Working Hours
$attenRec = $this->Attendance_Model->getAttendanceRecords($company_uid , $emp_uid, $d);
$signInHrs = 0;
$breakHrs = 0;
$workingHrs = 0;
for($i=0; $i<count($attenRec); $i++)
{
// Get this record's status
$status = $attenRec[$i]['status'];
// Get next record's status
if(!empty($attenRec[$i + 1]))
{
if($status == '1' || $status == '4') // Sign In or Break Over
{
$thisTime = strtotime($attenRec[$i]['atten_time']);
$nextTime = strtotime($attenRec[$i + 1]['atten_time']);
$diff = round(($nextTime - $thisTime) / 3600, 2);
$signInHrs += $diff;
}
if($status == '3') // Break Start
{
$thisTime = strtotime($attenRec[$i]['atten_time']);
$nextTime = strtotime($attenRec[$i + 1]['atten_time']);
$diff = round(($nextTime - $thisTime) / 3600, 2);
$signInHrs += $diff;
$breakHrs += $diff;
}
}
}
$onlySignInHrs = floor($signInHrs);
$remainingSignInHrs = $signInHrs - $onlySignInHrs;
$signInMinutes = round($remainingSignInHrs * 60);
$myAttendance['signInHrs'] = $onlySignInHrs . " Hrs : " . $signInMinutes . " Min";
$onlyBreakHrs = floor($breakHrs);
$remainingBreakHrs = $breakHrs - $onlyBreakHrs;
$breakMinutes = round($remainingBreakHrs * 60);
$myAttendance['breakHrs'] = $onlyBreakHrs . " Hrs : " . $breakMinutes . " Min";
$workingHrs = $signInHrs - $breakHrs;
$onlyWorkingHrs = floor($workingHrs);
$remainingWorkingHrs = $workingHrs - $onlyWorkingHrs;
$workingMinutes = round($remainingWorkingHrs * 60);
$myAttendance['workingHrs'] = $onlyWorkingHrs . " Hrs : " . $workingMinutes . " Min";
}
# Save This Date's Attendance
$atten[] = $myAttendance;
}
}
return $atten;
}

How to work out specific days and times within a date range

I have a database with a table of login and logoff times for staff.
Im looking for which staff clocked on or off between Sunday 6am and Thursday 4am or Saturday 6:30am and Saturday 3pm.
I want the end user to be able to select any date range from a web interface (ie 1/1/14 start and 12/1/14 end) and from this work out who worked during the day and time ranges.
I want to be able to display a list of workers and their login and logoff time.
thus far I have worked out how to check if a user has logged by using Determine Whether Two Date Ranges Overlap
But im stumped with the pseudo code for how to work out the daterangeB
so far I have:
start at datefrom,
check if datefrom = dateto, if true end loop,
find out day name,
check if saturday, if saturday add timestamps to array (start and finish),
increment datefrom by 1 day, start loop again.
this will give me an array of the saturday daterangeB's between the dates selected by the user.
However the bigger date range is an issue, because its possible that the first day is say a Tuesday, and if i'm checking for Sundays and Thursday, say i find a Thursday, i won't have a start day as sunday, I will need to make the Tuesday at 00:00:00. And similarly the opposite could happen, i could find a Sunday, and the last day that the user selects could be a Monday and therefore I need to make that the end date for daterangeB
start at datefrom,
check if datefrom = dateto, if true end loop,
find out day name,
check if Sunday, if Sunday add timestamp to array (start),
increment datefrom by 1 day, start loop again.
and
start at datefrom,
check if datefrom = dateto, if true end loop,
find out day name,
check if Thursday, if Thursday add timestamps to array (start and finish),
increment datefrom by 1 day, start loop again.
So for all those that are interested, here is a dumbed down verson of what i ended up doing:
$stcars = array();
// Create connection
try {
$db = new PDO('mysql:host=localhost;dbname=Reports;charset=utf8', 'XXX', 'XXX');
$db->query('hi'); //invalid query!
} catch(PDOException $ex) {
echo "An Error occured!" . $ex->getMessage(); //user friendly message
}
$stmt = $db->prepare('SELECT CarNumber FROM STcars WHERE CarNumber > 0');
if ($stmt->execute()){
while($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
array_push($stcars, $row[CarNumber]);
}// end while
}// end if
$DateFrom = $_POST["DateFrom"];
$DateTo = $_POST["DateTo"];
$DateToArray = date('m/d/Y', strtotime($DateTo . ' + 1 day'));
$period = new DatePeriod(
new DateTime($DateFrom),
new DateInterval('P1D'),
new DateTime($DateToArray)
);
foreach($period as $date)
{
$daterange[] = $date->format('m/d/Y');
}
// MS SQL Server with PDO_DBLIB
$DBH = new PDO("dblib:host=$myServer;dbname=$myDB", $myUser, $myPass);
for ($i = 0; $i < count($stcars); ++$i) {
$CarNumber = $stcars[$i];
$STH3 = $DBH->query("SELECT dbo.Driver.DriverNumber, dbo.Driver.DriverName, dbo.DriverLogon.LogonTime, dbo.DriverLogon.LogoffTime, dbo.Vehicle.RegistrationNumber, dbo.OwnerOperator.OOName FROM dbo.Driver INNER JOIN dbo.DriverLogon ON dbo.Driver.DriverID = dbo.DriverLogon.DriverID INNER JOIN dbo.Vehicle ON dbo.DriverLogon.VehicleID = dbo.Vehicle.VehicleID INNER JOIN dbo.OwnerOperator ON dbo.Vehicle.OperatorID = dbo.OwnerOperator.OwnerOperatorID WHERE dbo.Vehicle.CarNumber = '$CarNumber' AND dbo.DriverLogon.LogonTime >= '$DateFrom $Beginning' AND dbo.DriverLogon.LogoffTime <= '$DateTo $End' AND dbo.Driver.DriverNumber != '7777' AND dbo.Driver.DriverNumber != '83890';");
$STH3->setFetchMode(PDO::FETCH_OBJ);
while($row3 = $STH3->fetch()) {
$logonday = date("D", strtotime($row3->LogonTime));
$chkStartTime = strtotime($row3->LogonTime);
$chkEndTime = strtotime($row3->LogoffTime);
$Tplate = $row3->RegistrationNumber;
$Operator = $row3->OOName;
$logontime = gmdate("D d/m/Y H:i:s", strtotime($row3->LogonTime));
$logofftime = gmdate("D d/m/Y H:i:s", strtotime($row3->LogoffTime));
for ($e = 0; $e < count($daterange); ++$e) {
$Date = $daterange[$e];
$day = date("D", strtotime($Date));
if(strpos( $day, $Mon ) !== FALSE){
$startTime = strtotime($Date . " " . $Beginning);
$endTime = strtotime($Date . " " . $End);
if($chkStartTime >= $endTime || $chkEndTime <= $startTime){}else
{
echo "<tr>" ;
echo "<td>" . $day . "</td> ";
echo "<td>" . $row3->DriverNumber . "</td> ";
echo "<td>" . $row3->DriverName . "</td> ";
echo "<td>" . $Operator . "</td> ";
echo "<td>" . $CarNumber . "</td> ";
echo "<td>" . $Tplate . "</td> ";
echo "<td>" . $logontime . "</td> ";
echo "<td>" . $logofftime . "</td> ";
//echo "<td>" . "Logon after Time End or Logoff before Time Start" . "</td> ";
//echo "<td>" . gmdate("D d/m/Y G:i:s", strtotime($Date . " " . $Beginning)) . "</td> ";
//echo "<td>" . gmdate("D d/m/Y G:i:s", strtotime($Date . " " . $End)) . "</td> ";
echo "</tr>" ;
$list1 ="$day, $row3->DriverNumber, $row3->DriverName, $Operator, $CarNumber, $Tplate, $logontime, $logofftime " . "\n";
fwrite($handle, $list1);
}

Calculate days between 2 dates and another criterial PHP MYSQL

I'm new newbie to programming and I've got an error that i wasn't able to solve after hours searching.
I'm using a form to perform a search and display in a table the data, that part was fairly easy... but I also want to calculate how many days are in the final result, not in the dates I using for the first query.
The query searches for the result in days between 2 dates and from a specified company, the problem is in the final result it calculates how many days are from my result and not from the days i searched.
Example: If i search 2 dates between February 11 and February 20 Where the company = 1
If there is only 3 days result for Company 1, I want it to calculate only 3 Days.
I know my code is Wrong in that part but i just can't get it to do what i want.
Here is a little piece of my code to explain it:
if (isset($_POST['search'])) {
$date1 = mysql_prep($_POST['date1']);
$date2 = mysql_prep($_POST['date2']);
$latte = mysql_prep($_POST['latte']);
$query = "SELECT * FROM payroll WHERE (day BETWEEN '{$date1}' AND '{$date2}') AND (company = '{$latte}') ORDER BY day ASC ";
$result = mysql_query($query, $connection);
$woof = "SELECT SUM(hours) FROM (SELECT * FROM payroll WHERE (day BETWEEN '{$date1}' AND '{$date2}') AND (company = '{$latte}') ORDER BY day ASC) AS subt ";
$raw = mysql_query($woof, $connection);
if(!$raw) { die(mysql_error());}
$meow = mysql_result($raw, 0, 0);
$diff = abs(strtotime($date2) - strtotime($date1));
$years = floor($diff / (365*60*60*24));
$months = floor(($diff - $years * 365*60*60*24) / (30*60*60*24));
$days = floor(($diff - $years * 365*60*60*24 - $months*30*60*60*24)/ (60*60*24) +1);
if(!$result) {
echo "FAIL";
} else {
echo "<table>
<tr>
<th> Date </th>
<th> Hours </th>
<th> Job Title </th>
<th> Job Description </th>
<th> Paid </th>
<th> For </th>
</tr>";
while($row = mysql_fetch_array($result))
{
$company = $row['company'];
if($company == 0) {
$company = "Wilson Electric";
} if($company == 1) {
$company = "Wilson Rental";
} if ($company == 2) {
$company = "Church of Christ";
}
echo "<tr>";
echo "<td class=\"center\">" . $row['day'] . "</td>";
echo "<td class=\"center\">" . $row['hours'] . "</td>";
echo "<td style=\"padding:5px;\">" . $row['job_title'] . "</td>";
echo "<td style=\"padding:5px;\">" . $row['job_description'] . "</td>";
echo "<td class=\"center\">" . $row['paid'] . "</td>";
echo "<td style=\"padding:5px;\">" . $company . "</td>";
echo "</tr>";
}
echo "<tr>";
echo "<td class=\"center\"> Total Days: " . $days . "</td>";
echo "<td class=\"center\"> Total Hours: " . $meow . "</td>";
echo "</tr>";
}
}
Thanks for Reading it, I hope someone can give me a solution, i know must be something really simple but I just couldn't figure out.
If you want a count of distinct day values that match the specification, then you could add a simple expression to the SELECT list of the "woof" SQL statement:
SELECT SUM(hours), COUNT(DISTINCT `day`) AS cnt_days FROM ...
$meow = mysql_result($raw, 0, 0);
$days = mysql_result($raw, 0, 1);
Note that if there is more than one row that has the same day value (which satisfies all of the predicates), that day value is counted only once. If you want a count of rows that have a non-NULL day value, including any duplicates, then omit the DISTINCT keyword.)
Note that the SQL statement could be more simply written; you could omit the (unnecessary) inline view (i.e. derived table) and the unnecessary ORDER BY ...
SELECT SUM(p.hours) AS sum_hours
, COUNT(DISTINCT p.day) AS cnt_days
FROM payroll p
WHERE p.day BETWEEN '{$date1}' AND '{$date2}'
AND p.company = '{$latte}'
May be you can use DateTime::diff

Having trouble comparing a range of dates entered in a form with records in a mySQL database

I have a table called schedule and a column called Date where the column type is date. In that column I have a range of dates, which is currently from 2012-11-01 to 2012-11-30. I have a small form where the user can enter a range of dates (input names from and to) and I want to be able to compare the range of dates with the dates currently in the database.
This is what I have:
////////////////////////////////////////////////////////
//////First set the date range that we want to use//////
////////////////////////////////////////////////////////
if(isset($_POST['from']) && ($_POST['from'] != NULL))
{
$startDate = $_POST['from'];
}
else
{
//Default date is Today
$startDate = date("Y-m-d");
}
if(isset($_POST['to']) && ($_POST['to'] != NULL))
{
$endDate = $_POST['to'];
}
else
{
//Default day is one month from today
$endDate = date("Y-m-d", strtotime("+1 month"));
}
//////////////////////////////////////////////////////////////////////////////////////
//////Next calculate the total amount of days selected above to use as a limiter//////
//////////////////////////////////////////////////////////////////////////////////////
$dayStart = strtotime($startDate);
$dayEnd = strtotime($endDate);
$total_days = abs($dayEnd - $dayStart) / 86400 +1;
echo "Start Date: " . $startDate . "<br>End Date: " . $endDate . "<br>";
echo "Day Start: " . $dayStart . "<br>Day End: " . $dayEnd . "<br>";
echo "Total Days: " . $total_days . "<br>";
////////////////////////////////////////////////////////////////////////////////////
//////Then we're going to see if the dates selected are in the schedule table//////
////////////////////////////////////////////////////////////////////////////////////
//Select all of the dates currently in the schedule table between the range selected.
$sql = ("SELECT Date FROM schedule WHERE Date BETWEEN '$startDate' AND '$endDate' LIMIT $total_days");
//Run a check on the query to make sure it worked. If it failed then print the error.
if(!$result_date_query = $mysqli->query($sql))
{
die('There was an error getting the dates from the schedule table [' . $mysqli->error . ']');
}
//Set the dates to an array for future use.
// $current_dates = $result_date_query->fetch_assoc();
//Loop through the results while a result is being returned.
while($row = $result_date_query->fetch_assoc())
{
echo "Row: " . $row['Date'] . "<br>";
echo "Start day: " . date('Y-m-d', $dayStart) . "<br>";
//Set this loop to add 1 day to the Start Date until it reaches the End Date
for($i = $dayStart; $i <= $dayEnd; $i = strtotime('+1 day', $i))
{
$date = date('Y-m-d',$i);
echo "Loop Start day: " . date('Y-m-d', $dayStart) . "<br>";
//Run a check to see if any of the dates selected are in the schedule table.
if($row['Date'] != $date)
{
echo "Current Date: " . $row['Date'] . "<br>";
echo "Date: " . $date . "<br>";
echo "It appears as though you've selected some dates that are not in the schedule database.<br>Please correct the issue and try again.";
return;
}
}
}
//Free the result so something else can use it.
$result_date_query->free();
As you can see I've added in some echo statements so I can see what is being produced. From what I can see it looks like my $row['Date'] is not incrementing and staying at the same date. I originally had it set to a variable (currently commented out) but I thought that could be causing problems.
I have created the table with dates ranging from 2012-11-01 to 2012-11-15 for testing and entered all of this php code onto phpfiddle.org but I can't get the username provided to connect.
Here is the link: PHP Fiddle
I'll be reading through the documentation to try and figure out the user connection problem in the meantime, I would really appreciate any direction or advice you can give me.

how can i make any numbers above the month's total days appear as new month day numbers?

I have a php calendar at http://idea-palette.com/aleventcal/calendar.php.
I want the days that are not part of the current month to show up grayed out(which it does now), and I want it to appear as those are the days of the previous and next month.
As it is now, the days that appear before the first day of the month appear as negative numbers(-1,-2,-3, and so on) and the days that appear after the last day of the month just continue on, so if a month ends on the 31st, then it would read 32, 33, 34, and so on.
I'm trying to figure out a conditional statement with some sort of loop where I could see if it is greater than the total days and then do something else. The problem I see is that the table cell that is being created is being looped, so if I do just $day+1, then instead of 32, it will just read 33.
Here's my code:
for($i=0; $i< $total_rows; $i++)
{
for($j=0; $j<7;$j++)
{
$day++;
//if the current day is less or equal to the total days in the month
if($day>0 && $day<=$total_days_of_current_month)
{
$date_form = "$current_year/$current_month/$day";
echo '<div class="date_has_event" href="#"><td';
//If the date is today then give the td cell the 'today' class
if($date_form == $today)
{
echo ' class="today"';
}
//check if any event stored for the date
if(array_key_exists($day,$events))
{
//adding the date_has_event class to the <td> and close it
echo ' class="date_has_event">'.$day;
//adding the eventTitle and eventContent wrapped inside <span> & <li> to <ul>
echo '<div class="events"><ul>'.$events[$day].'</ul></div>';
}
}
else //if the current day is less or more than the total days in the month
{
//then create a table cell with the current day of the mont
echo '<td class="padding">' . $day . ' </td>'; h
}
}
}
just subtract the number of days in the current month of the day is positive:
else //if the current day is less or more than the total days in the month
{
if($day > 1){
echo '<td class="padding">' . ($day - $total_days_of_current_month) . ' </td>'; // the next month
} else {
echo '<td class="padding">' . $day . ' </td>'; //then create a table cell with the current day of the month
}
}
Here's part of a calendar function I recently wrote, you can hopefully get some ideas from it.
// $month is a UNIX timestamp
// resetting to 1st of the month
$date = getdate(mktime(0, 0, 0, date('n', $month), 1, date('Y', $month)));
// resetting to first day in grid
$date = getdate(strtotime("-$date[wday] days", $date[0]));
$out = array();
$lastDay = mktime(0, 0, 0, date('n', $month), date('t', $month), date('Y', $month));
while ($date[0] <= $lastDay) {
$row = array();
for ($x = 0; $x <= 6; $x++) {
$attr = array('class' => 'weekday '.low(date('D', $date[0])));
if (date('n', $month) != $date['mon']) {
$attr['class'].= ' prevNextMonth';
}
if (date('Y-m-d') == date('Y-m-d', $date[0])) {
$attr['class'].= ' today';
}
$row[] = array($date['mday'], $attr);
$date = getdate(strtotime("+1 day", $date[0]));
}
$out[] = $row;
}
// makes table rows out of the array, considers the $attr array as well
$out = $this->Html->tableCells($out);
$out = sprintf('<table><tbody>%s</tbody></table>', $out);
You don't need Steve's conditional: instead use
echo '<td class="padding">' . date("j",mktime(12,0,0,$current_month,$day,$current_year)) . ' </td>';
mktime handles out-of-range dates my moving them into the next or previous month, which is exactly what you want.

Categories